├── website ├── db.inc.php ├── config.inc.php ├── classes │ ├── Interfaces │ │ ├── View.php │ │ ├── Model.php │ │ ├── Singleton.php │ │ └── Listener.php │ ├── View │ │ ├── Readout.php │ │ ├── FrontpageInternal.php │ │ ├── Base.php │ │ └── Frontpage.php │ ├── Model │ │ ├── InternalReadout.php │ │ ├── Readout.php │ │ └── Base.php │ ├── General │ │ ├── StaticUtils.php │ │ ├── Statistics.php │ │ ├── Autoloader.php │ │ ├── Enviroment.php │ │ ├── Session.php │ │ ├── Config.php │ │ ├── GoogleChart.php │ │ ├── Templater.php │ │ ├── Formater.php │ │ └── Debug.php │ ├── Database │ │ ├── Config.php │ │ ├── Factory.php │ │ └── SQLiteWrapper.php │ ├── Translate │ │ ├── Controller.php │ │ └── Translate.php │ ├── Controller │ │ ├── Base.php │ │ ├── Frontpage.php │ │ └── Main.php │ ├── Cache │ │ ├── Factory.php │ │ ├── Variable.php │ │ ├── FileElement.php │ │ ├── Memcached.php │ │ ├── Session.php │ │ ├── Apc.php │ │ └── File.php │ └── Listeners │ │ ├── LowLevelMessage.php │ │ └── Message.php ├── .settings │ └── org.eclipse.php.core.prefs ├── css │ ├── index.css │ └── docs.css ├── index.php ├── assets │ └── bootstrap │ │ ├── img │ │ ├── glyphicons-halflings.png │ │ └── glyphicons-halflings-white.png │ │ └── css │ │ └── bootstrap-responsive.min.css ├── .buildpath ├── translations │ └── translations.php ├── js │ ├── engine.js │ └── form-validator.js ├── common.php ├── templates │ ├── chartHead.html │ ├── charts.html │ ├── tables.html │ ├── mainpage.html │ └── index.html └── .project ├── .gitignore ├── data.db ├── diagram.png ├── sensor_driver ├── assets └── img │ ├── 1.png │ ├── 2.jpg │ └── 3.png ├── run.sh ├── diagram.sch ├── compute_daily_aggregate.py ├── get_data.py ├── README.md ├── diagram.sch~ ├── sensor_driver.c └── diagram.ps /website/db.inc.php: -------------------------------------------------------------------------------- 1 | get(); 6 | -------------------------------------------------------------------------------- /website/assets/bootstrap/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DzikuVx/raspberry_temperature_log/HEAD/website/assets/bootstrap/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #set SHELL='/bin/bash' 2 | #set PWD='/home/pi/raspberry_temperature_log' 3 | 4 | set > /home/pi/run.log 5 | 6 | python /home/pi/raspberry_temperature_log/log_data.py 7 | 8 | -------------------------------------------------------------------------------- /website/assets/bootstrap/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DzikuVx/raspberry_temperature_log/HEAD/website/assets/bootstrap/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /website/classes/View/Readout.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /website/classes/View/FrontpageInternal.php: -------------------------------------------------------------------------------- 1 | aParams = $aParams; 14 | } 15 | 16 | /** 17 | * (non-PHPdoc) 18 | * @see Interfaces.View::get() 19 | */ 20 | public function get() { 21 | return ''; 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /website/templates/chartHead.html: -------------------------------------------------------------------------------- 1 | 2 | 16 | -------------------------------------------------------------------------------- /website/classes/General/StaticUtils.php: -------------------------------------------------------------------------------- 1 | array_slice(explode('\\', $name), 0, -1), 19 | 'classname' => join('', array_slice(explode('\\', $name), -1)), 20 | ); 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /website/templates/charts.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Last 72 hours

4 |
5 |
6 |
7 |
8 | 9 | 10 |
11 |
12 |

Last 14 days

13 |
14 |
15 |
16 |
-------------------------------------------------------------------------------- /website/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | pi_temperature 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.validation.validationbuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.dltk.core.scriptbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.php.core.PHPNature 21 | 22 | 23 | -------------------------------------------------------------------------------- /website/classes/Database/Config.php: -------------------------------------------------------------------------------- 1 | Singleton 14 | * @return Config 15 | */ 16 | public static function getInstance() { 17 | 18 | if (empty(self::$instance)) { 19 | self::$instance = new self(); 20 | } 21 | 22 | return self::$instance; 23 | } 24 | 25 | protected function parse() { 26 | 27 | require (dirname ( __FILE__ ) . "/../../db.inc.php"); 28 | 29 | $this->config = $config; 30 | 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /website/classes/Database/Factory.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Daily stats

4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | {DailyTable} 22 | 23 |
 {T:Temperature}{T:Humidity}
{T:Date}{T:Min.}{T:Avg.}{T:Max.}{T:Min.}{T:Avg.}{T:Max.}
24 |
25 | 26 |
27 |
28 |

{T:Readouts history}

29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | {Table} 39 | 40 |
#{T:Date}{T:Temperature}{T:Humidity}
41 |
42 |
-------------------------------------------------------------------------------- /website/classes/General/Statistics.php: -------------------------------------------------------------------------------- 1 | $m, "b"=>$b); 39 | 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /website/classes/Translate/Controller.php: -------------------------------------------------------------------------------- 1 | get('memcachedIP'); 32 | \Cache\Memcached::$port = Config::getInstance()->get('memcachedPort'); 33 | 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /website/classes/General/Session.php: -------------------------------------------------------------------------------- 1 | table[$offset])) { 55 | return $_SESSION[self::$prefix.$offset]; 56 | }else { 57 | return false; 58 | } 59 | 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /website/templates/mainpage.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 |

{T:Temperature}

7 |

{Temperature}°C

8 |

24h average: {1dTempAvg}°C

9 |

24h min: {1dTempMin}°C

10 |

24h max: {1dTempMax}°C

11 |

7d average: {7dTempAvg}°C

12 |

7d min: {7dTempMin}°C

13 |

7d max: {7dTempMax}°C

14 |
15 |
16 |

{T:Humidity}

17 |

{Humidity}%

18 |

24h average: {1dHumidityAvg}%

19 |

24h min: {1dHumidityMin}%

20 |

24h max: {1dHumidityMax}%

21 |

7d average: {7dHumidityAvg}%

22 |

7d min: {7dHumidityMin}%

23 |

7d max: {7dHumidityMax}%

24 |
25 |
26 |
27 | 28 | 37 | 38 | {pageContent} 39 | 40 |
41 |
42 |
-------------------------------------------------------------------------------- /diagram.sch: -------------------------------------------------------------------------------- 1 | v 20110115 2 2 | C 40000 40000 0 0 0 title-B.sym 3 | C 41500 49900 1 0 0 input-1.sym 4 | { 5 | T 41500 50200 5 10 0 0 0 0 1 6 | device=INPUT 7 | } 8 | C 41500 46900 1 0 0 input-1.sym 9 | { 10 | T 41500 47200 5 10 0 0 0 0 1 11 | device=INPUT 12 | } 13 | C 41500 48400 1 0 0 input-1.sym 14 | { 15 | T 41500 48700 5 10 0 0 0 0 1 16 | device=INPUT 17 | } 18 | C 46500 50100 1 180 0 input-1.sym 19 | { 20 | T 46500 49800 5 10 0 0 180 0 1 21 | device=Vcc 22 | } 23 | C 46500 48600 1 180 0 input-1.sym 24 | { 25 | T 46500 48300 5 10 0 0 180 0 1 26 | device=INPUT 27 | } 28 | C 46500 47100 1 180 0 input-1.sym 29 | { 30 | T 46500 46800 5 10 0 0 180 0 1 31 | device=INPUT 32 | } 33 | T 41300 50400 9 10 1 0 0 0 1 34 | Raspberry Pi 35 | T 45900 50300 9 10 1 0 0 0 1 36 | DHT11 37 | T 46700 50000 9 10 1 0 0 0 1 38 | Vcc 39 | T 46700 48500 9 10 1 0 0 0 1 40 | Sig 41 | T 46700 47000 9 10 1 0 0 0 1 42 | GND 43 | T 40800 50000 9 10 1 0 0 0 1 44 | 3.3V [1] 45 | T 40700 47000 9 10 1 0 0 0 1 46 | GND [6] 47 | T 40600 48600 9 10 1 0 0 0 1 48 | GPIO4 [7] 49 | N 42300 50000 45700 50000 4 50 | C 42900 48900 1 90 0 resistor-1.sym 51 | { 52 | T 42500 49200 5 10 0 0 90 0 1 53 | device=RESISTOR 54 | T 42600 49100 5 10 1 1 90 0 1 55 | refdes=10k 56 | } 57 | N 42800 49800 42800 50000 4 58 | N 42300 48500 45700 48500 4 59 | N 42800 48900 42800 48500 4 60 | N 42300 47000 45700 47000 4 61 | -------------------------------------------------------------------------------- /website/classes/General/Config.php: -------------------------------------------------------------------------------- 1 | config; 19 | } 20 | 21 | /** 22 | * Konstruktor statyczny -> Singleton 23 | * @return Config 24 | */ 25 | public static function getInstance() { 26 | 27 | if (empty(self::$instance)) { 28 | self::$instance = new self(); 29 | } 30 | 31 | return self::$instance; 32 | } 33 | 34 | public function offsetSet($offset, $value) { 35 | $this->config[$offset] = $value; 36 | } 37 | 38 | public function offsetExists($offset) { 39 | return isset($this->config[$offset]); 40 | } 41 | 42 | public function offsetUnset($offset) { 43 | unset($this->config[$offset]); 44 | } 45 | 46 | public function offsetGet($offset) { 47 | 48 | if (isset($this->config[$offset])) { 49 | return $this->config[$offset]; 50 | }else { 51 | return false; 52 | } 53 | 54 | } 55 | 56 | public function get($offset) { 57 | return $this->offsetGet($offset); 58 | } 59 | 60 | protected function parse() { 61 | 62 | require (dirname ( __FILE__ ) . "/../../config.inc.php"); 63 | 64 | $this->config = $config; 65 | 66 | } 67 | 68 | protected function __construct() { 69 | $this->parse(); 70 | } 71 | 72 | 73 | 74 | } -------------------------------------------------------------------------------- /website/classes/Controller/Base.php: -------------------------------------------------------------------------------- 1 | aExcluded,$this->aGlobalExcluded); 26 | } 27 | 28 | private static $instance; 29 | 30 | /** 31 | * Konstruktor prywatny 32 | */ 33 | private function __construct() 34 | { 35 | 36 | } 37 | 38 | static public function getInstance() 39 | { 40 | 41 | if (empty(self::$instance)) { 42 | self::$instance = new self(); 43 | } 44 | 45 | if (empty(self::$instance)) { 46 | throw new \Exception('Base controller was unable to initiate'); 47 | } 48 | 49 | return self::$instance; 50 | } 51 | 52 | 53 | static public function formatLink(array $aParams, $sAmp = true, $bOnClick = false) 54 | { 55 | $sRetVal = ''; 56 | 57 | foreach ($aParams as $sKey => $sValue) { 58 | $sRetVal .= $sKey . '/' . $sValue; 59 | } 60 | 61 | $sRetVal = \General\Config::getInstance()->get('baseUrl') . $sRetVal; 62 | return $sRetVal; 63 | } 64 | 65 | } -------------------------------------------------------------------------------- /website/classes/Cache/Factory.php: -------------------------------------------------------------------------------- 1 | get('cacheMethod'); 35 | 36 | if ($sCachingMethod === 'apc' && !(extension_loaded('apc') && ini_get('apc.enabled'))) { 37 | $sCachingMethod = 'Mem'; 38 | } 39 | 40 | switch ($sCachingMethod) { 41 | 42 | case 'Apc': 43 | self::$cacheInstance = Apc::getInstance(); 44 | break; 45 | 46 | case 'Memcached': 47 | self::$cacheInstance = Memcached::getInstance(); 48 | break; 49 | 50 | default: 51 | self::$cacheInstance = Variable::getInstance(); 52 | break; 53 | 54 | } 55 | 56 | } 57 | 58 | } 59 | 60 | /** 61 | * Pobranie obiektu klasy cacheującej 62 | * @throws Exception 63 | * @return Memcached 64 | */ 65 | static public function getInstance() { 66 | 67 | if (empty(self::$cacheInstance)) { 68 | self::create(); 69 | } 70 | 71 | if (empty(self::$cacheInstance)) { 72 | throw new \Exception('Cache object is not initialized'); 73 | } 74 | 75 | return self::$cacheInstance; 76 | } 77 | 78 | 79 | } -------------------------------------------------------------------------------- /website/classes/Translate/Translate.php: -------------------------------------------------------------------------------- 1 | language = $language; 30 | 31 | if (!self::$useCache || ! Cache::getInstance()->check ( 'translationList', $this->language )) { 32 | require dirname ( __FILE__ ).'/../../translations/'.$file; 33 | 34 | $this->table = $translationTable [$this->language]; 35 | unset ( $translationTable ); 36 | 37 | if (self::$useCache) { 38 | Cache::getInstance()->set ( 'translationList', $this->language, $this->table, 86400 ); 39 | } 40 | } else { 41 | $this->table = Cache::getInstance()->get ( 'translationList', $this->language ); 42 | } 43 | 44 | } 45 | 46 | /** 47 | * Pobranie tłumaczenia 48 | * 49 | * @param string $string 50 | * @return string 51 | */ 52 | function get($string) { 53 | 54 | if (isset ( $this->table [$string] )) { 55 | return $this->table [$string]; 56 | } else { 57 | return $string; 58 | } 59 | } 60 | 61 | public function offsetSet($offset, $value) { 62 | $this->table[$offset] = $value; 63 | } 64 | 65 | public function offsetExists($offset) { 66 | return isset($this->table[$offset]); 67 | } 68 | 69 | public function offsetUnset($offset) { 70 | unset($this->table[$offset]); 71 | } 72 | 73 | public function offsetGet($offset) { 74 | 75 | if (isset($this->table[$offset])) { 76 | return $this->table[$offset]; 77 | }else { 78 | return false; 79 | } 80 | 81 | } 82 | 83 | } -------------------------------------------------------------------------------- /website/classes/General/GoogleChart.php: -------------------------------------------------------------------------------- 1 | title = $title; 14 | } 15 | 16 | public function setDomID($domID) { 17 | $this->domID = $domID; 18 | } 19 | 20 | public function add($title, $data) { 21 | $this->data[$title] = $data; 22 | } 23 | 24 | public function push($title, $value) { 25 | array_push($this->data[$title], $value); 26 | } 27 | 28 | public function getHead() { 29 | 30 | $sRetVal = ''; 31 | 32 | $aKeys = array_keys($this->data); 33 | 34 | $aOutKeys = array(); 35 | foreach ($aKeys as $key=>$value) { 36 | $aOutKeys[$key] = "'".$value."'"; 37 | } 38 | 39 | $sRetVal .= "var data = google.visualization.arrayToDataTable(["; 40 | $sRetVal .= "[ ".implode(", ", $aOutKeys)."]"; 41 | 42 | $iLength = count($this->data[$aKeys[0]]); 43 | 44 | for ($i = 0; $i < $iLength; $i++) { 45 | $aTemp = array(); 46 | 47 | foreach ($aKeys as $key=>$value) { 48 | 49 | $chartVal = $this->data[$aKeys[$key]][$i]; 50 | 51 | if (!is_numeric($chartVal)) { 52 | $chartVal = "'".$chartVal."'"; 53 | } 54 | 55 | array_push($aTemp, $chartVal); 56 | } 57 | 58 | $sRetVal .= ", [ ".implode(", ", $aTemp)."]"; 59 | } 60 | 61 | $sRetVal .= "]);"; 62 | 63 | $sRetVal .= "\n\rvar options = { 64 | title : '{$this->title}', 65 | legend: {position: 'right'} 66 | };"; 67 | 68 | $sRetVal .= "\n\rvar chart = new google.visualization.LineChart(document 69 | .getElementById('{$this->domID}')); 70 | chart.draw(data, options);"; 71 | 72 | 73 | return $sRetVal; 74 | 75 | } 76 | 77 | } -------------------------------------------------------------------------------- /website/js/form-validator.js: -------------------------------------------------------------------------------- 1 | var FormValidators = function() { 2 | 3 | }; 4 | 5 | /** 6 | * Maska pól 7 | * 8 | * @param object 9 | * @param type 10 | */ 11 | FormValidators.mask = function(object, type) { 12 | 13 | var original = ''; 14 | var str = ''; 15 | 16 | original = $(object).val(); 17 | str = original; 18 | 19 | if (type == 'number' || type == 0) { 20 | var valid = "0123456789"; 21 | var temp; 22 | var new_str; 23 | new_str = ""; 24 | 25 | for ( var i = 0; i < str.length; i++) { 26 | temp = "" + str.substring(i, i + 1); 27 | if (valid.indexOf(temp) != "-1") { 28 | new_str = new_str + temp; 29 | } 30 | } 31 | 32 | str = new_str; 33 | } 34 | 35 | if (type == 'binumber' || type == 1) { 36 | var valid = ",0123456789"; 37 | var temp; 38 | var new_str; 39 | new_str = ""; 40 | 41 | for ( var i = 0; i < str.length; i++) { 42 | temp = "" + str.substring(i, i + 1); 43 | if (valid.indexOf(temp) != "-1") { 44 | new_str = new_str + temp; 45 | } 46 | } 47 | 48 | var dotPoint = FormValidators.strpos(new_str, ',',0); 49 | 50 | if (dotPoint) { 51 | new_str = new_str.slice(0,dotPoint+3); 52 | } 53 | 54 | str = new_str; 55 | } 56 | 57 | if ($(object).attr('size')) { 58 | 59 | if (str.length > $(object).attr('size')) { 60 | str = str.substring(0, $(object).attr('size')); 61 | } 62 | 63 | } 64 | 65 | if ($(object).attr('max')) { 66 | 67 | if (parseInt(str) > parseInt($(object).attr('max'))) { 68 | str = $(object).attr('max'); 69 | } 70 | 71 | } 72 | 73 | if ($(object).attr('min')) { 74 | 75 | if (parseInt(str) < parseInt($(object).attr('min'))) { 76 | str = $(object).attr('min'); 77 | } 78 | 79 | } 80 | 81 | if (original != str) { 82 | $(object).val(str); 83 | } 84 | 85 | }; 86 | 87 | FormValidators.strpos = function (haystack, needle, offset) { 88 | var i = (haystack + '').indexOf(needle, (offset || 0)); 89 | return i === -1 ? false : i; 90 | }; -------------------------------------------------------------------------------- /compute_daily_aggregate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | ''' 5 | Raspberry Pi Temperature and Humidity logger using DHT11 Sensor 6 | Paweł Spychalski 7 | http://www.spychalski.info 8 | ''' 9 | 10 | import sqlite3 11 | import sys 12 | import os 13 | import getopt 14 | import logging 15 | import datetime 16 | 17 | def computeSensor(sensor, dayMinus): 18 | 19 | conn = sqlite3.connect(os.path.dirname(os.path.realpath(__file__)) + '/data.db') 20 | 21 | c = conn.cursor() 22 | 23 | #Create missing tables 24 | c.execute('CREATE TABLE IF NOT EXISTS daily_aggregate(`Sensor` text, `Date` text, AvgTemperature real, AvgHumidity real, MinTempetaure real, MinHumidity real, MaxTemperature real, MaxHumidity real)') 25 | 26 | #Drop data for that day 27 | c.execute("DELETE FROM daily_aggregate WHERE `Sensor`='"+sensor+"' AND date(`Date`)=(SELECT date('now','-"+str(dayMinus)+" day'))") 28 | 29 | if sensor == "internal": 30 | tableName = "readouts" 31 | elif sensor == "external": 32 | tableName = "readouts_external" 33 | else: 34 | logging.error('Unknown sensor ' + sensor) 35 | sys.exit(2) 36 | 37 | c.execute("INSERT INTO daily_aggregate SELECT '" + sensor + "', date(`Date`), Avg(Temperature), Avg(Humidity), Min(Temperature), Min(Humidity), Max(Temperature), Max(Humidity) FROM " + tableName + " WHERE date(`Date`)=(SELECT date('now','-" + str(dayMinus) + " day'))") 38 | 39 | conn.commit() 40 | conn.close() 41 | 42 | def main(args): 43 | 44 | logging.basicConfig(filename=os.path.dirname(os.path.realpath(__file__)) + '/aggregate.log',level=logging.ERROR) 45 | 46 | dayMinus = 1; 47 | 48 | logging.info('Started at ' + datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')); 49 | 50 | try: 51 | options, arguments = getopt.getopt(args, "d:") 52 | except getopt.GetoptError: 53 | usage() 54 | sys.exit(2) 55 | 56 | for arg in options: 57 | 58 | if arg[0] == "-d": 59 | dayMinus = int(arg[1]); 60 | 61 | computeSensor('internal', dayMinus) 62 | computeSensor('external', dayMinus) 63 | 64 | if __name__ == "__main__": 65 | main(sys.argv[1:]) -------------------------------------------------------------------------------- /website/classes/Controller/Frontpage.php: -------------------------------------------------------------------------------- 1 | execute($aParams, $template); 42 | 43 | Main::$mainContentProcessed = true; 44 | 45 | } 46 | } 47 | 48 | } 49 | 50 | } 51 | 52 | public function render(array $aParams, \General\Templater $template) { 53 | 54 | if (empty($aParams['type'])) { 55 | $aParams['type'] = 'chart'; 56 | } 57 | 58 | $oView = new \View\FrontpageInternal($aParams); 59 | $template->add('menu-active-internal','active'); 60 | 61 | $template->add('mainContent', $oView->mainpage()); 62 | 63 | switch ($aParams['type']) { 64 | 65 | case 'table': 66 | $template->add('pageContent', $oView->tables()); 67 | $template->add('menu-active-table','active'); 68 | break; 69 | 70 | case 'chart': 71 | default: 72 | $template->add('chartHead', $oView->chartHead()); 73 | $template->add('pageContent', $oView->charts()); 74 | $template->add('menu-active-chart','active'); 75 | break; 76 | 77 | } 78 | 79 | $template->add('menu-active-external', ''); 80 | $template->add('menu-active-internal', ''); 81 | $template->add('menu-active-table',''); 82 | $template->add('menu-active-chart',''); 83 | 84 | } 85 | } -------------------------------------------------------------------------------- /website/classes/Cache/Variable.php: -------------------------------------------------------------------------------- 1 | cache [$module] [$property] )) { 46 | $this->cacheCount += 1; 47 | } 48 | 49 | //Wstaw wartość cache 50 | $this->cache [$module] [$property] = $value; 51 | 52 | return true; 53 | } 54 | 55 | /** 56 | * Sprawdzenie, czy istnieje wpis w cache 57 | * @param $module 58 | * @param $property 59 | * @return boolean 60 | */ 61 | function check($module, $property) { 62 | 63 | if (isset ( $this->cache [$module] [$property] )) { 64 | return true; 65 | } else { 66 | return false; 67 | } 68 | } 69 | 70 | /** 71 | * Pobranie pozycji z cache 72 | * @param $module 73 | * @param $property 74 | * @return wartość 75 | */ 76 | function get($module, $property) { 77 | 78 | if (isset ( $this->cache [$module] [$property] )) { 79 | $tTemp = $this->cache [$module] [$property]; 80 | return $tTemp; 81 | } else { 82 | return null; 83 | } 84 | } 85 | 86 | public function clear($module, $property) { 87 | return true; 88 | } 89 | 90 | /** 91 | * Wyświetla tablicę cache 92 | */ 93 | function debug() { 94 | 95 | \psDebug::print_r ( $this->cache ); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /website/classes/Cache/FileElement.php: -------------------------------------------------------------------------------- 1 | 9 | * @see http://www.spychalski.info 10 | * @see CacheOverFile 11 | * @category Common 12 | * @version 0.9 13 | */ 14 | class FileElement{ 15 | /** 16 | * Wartość wpisu 17 | * 18 | * @var mixed 19 | */ 20 | protected $value = null; 21 | 22 | /** 23 | * Czas ważności wpisu 24 | * 25 | * @var int 26 | */ 27 | protected $time = null; 28 | 29 | /** 30 | * Identyfikator użytkownika ustawiającego wpis 31 | * 32 | * @var int 33 | */ 34 | protected $userID = null; 35 | 36 | /** 37 | * Czy wpis uległ zmianie 38 | * 39 | * @var boolean 40 | */ 41 | protected $changed = false; 42 | 43 | /** 44 | * @return int 45 | */ 46 | public function getTime() { 47 | 48 | return $this->time; 49 | } 50 | 51 | /** 52 | * @param int $time 53 | */ 54 | public function setTime($time) { 55 | 56 | $this->changed = true; 57 | $this->time = $time; 58 | } 59 | 60 | /** 61 | * @return mixed 62 | */ 63 | public function getValue() { 64 | 65 | return $this->value; 66 | } 67 | 68 | /** 69 | * @param mixed $value 70 | */ 71 | public function setValue($value) { 72 | 73 | $this->changed = true; 74 | 75 | $this->value = $value; 76 | } 77 | 78 | /** 79 | * Konstruktor 80 | * 81 | * @param mixed $value 82 | * @param int $time 83 | * @param int $userID 84 | * @param boolean $changed 85 | */ 86 | function __construct($value, $time, $userID = null, $changed = true) { 87 | 88 | $this->value = $value; 89 | $this->time = $time; 90 | $this->userID = $userID; 91 | $this->changed = $changed; 92 | } 93 | 94 | /** 95 | * Ustawienie wpisu 96 | * 97 | * @param mixed $value 98 | * @param int $time 99 | * @param int $userID 100 | */ 101 | public function set($value, $time, $userID = null) { 102 | 103 | if ($this->value != $value || $this->userID != $userID || $this->time != $time) { 104 | $this->changed = true; 105 | } 106 | $this->value = $value; 107 | $this->time = $time; 108 | $this->userID = $userID; 109 | } 110 | 111 | } -------------------------------------------------------------------------------- /get_data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | ''' 5 | Raspberry Pi Temperature and Humidity logger using DHT11 Sensor 6 | Paweł Spychalski 7 | http://www.spychalski.info 8 | ''' 9 | 10 | import subprocess 11 | import time 12 | import sqlite3 13 | import os 14 | 15 | db_host = "localhost" 16 | db_user = "pi_temperature" 17 | db_password = "pi_temperature" 18 | db_name = "pi_temperature" 19 | 20 | def getReadout(type): 21 | 22 | if type == "internal": 23 | p = subprocess.Popen('sudo /home/pi/raspberry_temperature_log/sensor_driver 11 4', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 24 | elif type == "external": 25 | p = subprocess.Popen('sudo /home/pi/raspberry_temperature_log/sensor_driver 2302 17', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 26 | else: 27 | return None 28 | 29 | for line in p.stdout.readlines(): 30 | 31 | if len(line) < 2 or len(line) > 10: 32 | print "Error from driver: " + line 33 | return None 34 | else: 35 | return line.split("|") 36 | 37 | 38 | 39 | def saveSQLite(data, type): 40 | 41 | conn = sqlite3.connect(os.path.dirname(os.path.realpath(__file__)) + '/data.db') 42 | 43 | if type == "internal": 44 | 45 | c = conn.cursor() 46 | c.execute('CREATE TABLE IF NOT EXISTS readouts(`Date` text, Temperature real, Humidity real)') 47 | 48 | c.execute("INSERT INTO readouts(`Date`, Humidity, Temperature) VALUES(datetime('now','localtime'), "+data[0]+","+data[1]+")") 49 | 50 | elif type == "external": 51 | c = conn.cursor() 52 | c.execute('CREATE TABLE IF NOT EXISTS readouts_external(`Date` text, Temperature real, Humidity real)') 53 | 54 | c.execute("INSERT INTO readouts_external(`Date`, Humidity, Temperature) VALUES(datetime('now','localtime'), "+data[0]+","+data[1]+")") 55 | else: 56 | return 57 | 58 | conn.commit() 59 | conn.close() 60 | 61 | def main(): 62 | 63 | print "Internal Sensor:" 64 | 65 | readout = None 66 | 67 | counter = 0 68 | 69 | while (readout == None and counter < 5): 70 | 71 | counter += 1 72 | 73 | readout = getReadout("internal") 74 | 75 | if readout != None: 76 | 77 | saveSQLite(readout, "internal") 78 | 79 | humidity = readout[0] 80 | temperature = readout[1] 81 | 82 | print "Humidity: " + humidity 83 | print "Temperature: " + temperature 84 | else: 85 | time.sleep(1) 86 | 87 | if __name__ == "__main__": 88 | main() 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # raspberry_temperature_log 2 | 3 | ## This project is no longer supported. For more advanced solution refer to https://github.com/DzikuVx/WeatherStation 4 | 5 | Turn Raspberry Pi into temperature and humidity logging station with DHT11 sensor 6 | 7 | ![screenshot](/assets/img/3.png) 8 | ![raspberry with sensor](/assets/img/2.jpg) 9 | 10 | #Electrical diagram 11 | 12 | ![diagram](diagram.png) 13 | 14 | ## Requirements 15 | 16 | * BCM2835 C Library 17 | * python 18 | * php5 with SQLite3 enabled 19 | * SQLite3 20 | * any web server: nginx recomended 21 | 22 | # Installation 23 | 24 | * Do electrical stuff like showed on diagram. It's really simple 25 | * check if you have SQLite3 PHP library. If not, or not sure, install it `sudo apt-get install php5-sqlite3` 26 | * check if you have BCM2835 C Library installed. If not, setup instruction is in the next paragraph 27 | * clone this repository `git clone https://github.com/DzikuVx/raspberry_temperature_log.git` 28 | * `cd raspberry_temperature_log` 29 | * build sensor driver `sh build_sensor.sh` 30 | * check if sensors are working `python get_data.py` 31 | * add following line to cron (with `crontab -e`), it will get save data do database every 20 minutes: `*/20 * * * * sudo python /home/pi/raspberry_temperature_log/get_data.py` 32 | * configure Raspberry Pi web server, example configuration for nginx, PHP5-FMP and domain http://temperature.spychalski.info included below 33 | * that's all 34 | 35 | # BCM2835 C Library installation 36 | 37 | * `wget http://www.open.com.au/mikem/bcm2835/bcm2835-1.8.tar.gz` 38 | * `tar -zxvf bcm2835-1.8.tar.gz` 39 | * `cd bcm2835-1.8` 40 | * `./configure` 41 | * `make` 42 | * `sudo make install` 43 | 44 | ## Example nginx configuration 45 | 46 | ``` 47 | server { 48 | listen 0.0.0.0:80; 49 | 50 | server_name temperature.spychalski.info; 51 | 52 | access_log off; 53 | 54 | root /home/pi/raspberry_temperature_log/website; 55 | index index.php; 56 | 57 | # default try order 58 | location / { 59 | try_files $uri $uri/ /index.php?$args; 60 | } 61 | 62 | # enable php 63 | location ~ \.php$ { 64 | fastcgi_pass unix:/var/run/php5-fpm.sock; 65 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 66 | include fastcgi_params; 67 | } 68 | } 69 | 70 | ``` 71 | 72 | ## Legal stuff 73 | 74 | sensor_driver.c readout is based on https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code/tree/master/Adafruit_DHT_Driver by Adafruit 75 | -------------------------------------------------------------------------------- /website/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {pageTitle} 7 | 8 | 9 | 10 | 11 | 14 | 15 | 17 | 18 | 19 | 20 | {chartHead} 21 | 22 | 23 | 24 | 29 | 30 | 31 | 32 | 44 |
45 |
46 |
{listeners}
47 |
48 |
49 | {mainContent} 50 | 51 | 64 | 65 | -------------------------------------------------------------------------------- /diagram.sch~: -------------------------------------------------------------------------------- 1 | v 20110115 2 2 | C 40000 40000 0 0 0 title-B.sym 3 | C 41500 49900 1 0 0 input-1.sym 4 | { 5 | T 41500 50200 5 10 0 0 0 0 1 6 | device=INPUT 7 | } 8 | C 41500 46400 1 0 0 input-1.sym 9 | { 10 | T 41500 46700 5 10 0 0 0 0 1 11 | device=INPUT 12 | } 13 | C 41500 48500 1 0 0 input-1.sym 14 | { 15 | T 41500 48800 5 10 0 0 0 0 1 16 | device=INPUT 17 | } 18 | C 41500 48000 1 0 0 input-1.sym 19 | { 20 | T 41500 48300 5 10 0 0 0 0 1 21 | device=INPUT 22 | } 23 | C 46500 50100 1 180 0 input-1.sym 24 | { 25 | T 46500 49800 5 10 0 0 180 0 1 26 | device=Vcc 27 | } 28 | C 46500 49600 1 180 0 input-1.sym 29 | { 30 | T 46500 49300 5 10 0 0 180 0 1 31 | device=INPUT 32 | } 33 | C 46500 49100 1 180 0 input-1.sym 34 | { 35 | T 46500 48800 5 10 0 0 180 0 1 36 | device=INPUT 37 | } 38 | C 46500 47600 1 180 0 input-1.sym 39 | { 40 | T 46500 47300 5 10 0 0 180 0 1 41 | device=INPUT 42 | } 43 | C 46500 47100 1 180 0 input-1.sym 44 | { 45 | T 46500 46800 5 10 0 0 180 0 1 46 | device=INPUT 47 | } 48 | C 46500 46600 1 180 0 input-1.sym 49 | { 50 | T 46500 46300 5 10 0 0 180 0 1 51 | device=INPUT 52 | } 53 | T 41300 50400 9 10 1 0 0 0 1 54 | Raspberry Pi 55 | T 45900 50300 9 10 1 0 0 0 1 56 | DHT11 57 | T 45900 47800 9 10 1 0 0 0 1 58 | DHT22 59 | T 46700 50000 9 10 1 0 0 0 1 60 | Vcc 61 | T 46700 49500 9 10 1 0 0 0 1 62 | Sig 63 | T 46700 49000 9 10 1 0 0 0 1 64 | GND 65 | T 46700 47500 9 10 1 0 0 0 1 66 | Vcc 67 | T 46700 47000 9 10 1 0 0 0 1 68 | Sig 69 | T 46700 46500 9 10 1 0 0 0 1 70 | GND 71 | T 40800 50000 9 10 1 0 0 0 1 72 | 3.3V [1] 73 | T 40700 46500 9 10 1 0 0 0 1 74 | GND [6] 75 | T 40600 48600 9 10 1 0 0 0 1 76 | GPIO4 [7] 77 | T 40400 48100 9 10 1 0 0 0 1 78 | GPIO17 [11] 79 | N 42300 50000 45700 50000 4 80 | N 44100 50000 44100 47500 4 81 | N 44100 47500 45700 47500 4 82 | C 42900 48900 1 90 0 resistor-1.sym 83 | { 84 | T 42500 49200 5 10 0 0 90 0 1 85 | device=RESISTOR 86 | T 42600 49100 5 10 1 1 90 0 1 87 | refdes=10k 88 | } 89 | C 43600 48900 1 90 0 resistor-1.sym 90 | { 91 | T 43200 49200 5 10 0 0 90 0 1 92 | device=RESISTOR 93 | T 43300 49100 5 10 1 1 90 0 1 94 | refdes=10k 95 | } 96 | N 42800 49800 42800 50000 4 97 | N 43500 50000 43500 49800 4 98 | N 42300 48600 44500 48600 4 99 | N 44500 48600 44500 49500 4 100 | N 44500 49500 45700 49500 4 101 | N 42300 48100 44500 48100 4 102 | N 44500 48100 44500 47000 4 103 | N 44500 47000 45700 47000 4 104 | N 42800 48900 42800 48600 4 105 | N 43500 48900 43500 48100 4 106 | N 45700 49000 45000 49000 4 107 | N 45000 49000 45000 46500 4 108 | N 42300 46500 45700 46500 4 109 | -------------------------------------------------------------------------------- /website/classes/Listeners/LowLevelMessage.php: -------------------------------------------------------------------------------- 1 | message = $aArray; 42 | } 43 | 44 | /** 45 | * 46 | * Pobranie tablicy kolejki 47 | * @return array 48 | */ 49 | private function get() { 50 | return $this->message; 51 | } 52 | 53 | /** 54 | * Wyczyszczenie kolejki komunikatów 55 | */ 56 | private function clear() { 57 | $this->set(null); 58 | } 59 | 60 | /** 61 | * Wstawienie komunikatu do kolejki 62 | * @param string $sType success/info/warning/error 63 | * @param string $sMessage 64 | */ 65 | public function push($sType, $sMessage) { 66 | $aArray = $this->get(); 67 | 68 | if (empty($aArray)) { 69 | $aArray = array(); 70 | } 71 | 72 | array_push($aArray, array('type'=>$sType,'message'=>$sMessage)); 73 | $this->set($aArray); 74 | } 75 | 76 | /** 77 | * Utworzenie kodu HTML z wiadomością 78 | * @param array $aMessage 79 | * @return string 80 | */ 81 | private function render(array $aMessage) { 82 | 83 | 84 | switch ($aMessage['type']) { 85 | 86 | case 'success': 87 | $sClass = 'alert alert-success'; 88 | break; 89 | 90 | case 'info': 91 | $sClass = 'alert alert-info'; 92 | break; 93 | 94 | case 'error': 95 | $sClass = 'alert alert-error'; 96 | break; 97 | 98 | default: 99 | $sClass = 'alert'; 100 | break; 101 | 102 | } 103 | 104 | $sHtml = '
'.$aMessage['message'].'
'; 105 | 106 | return $sHtml; 107 | } 108 | 109 | /** 110 | * Rejestracja listenera 111 | * @param array $aParams 112 | * @param \General\Templater $template 113 | */ 114 | public function register(array &$aParams, \General\Templater $template) { 115 | 116 | $aArray = $this->get(); 117 | 118 | if (empty($aArray)) { 119 | return; 120 | } 121 | 122 | $sHtml = ''; 123 | 124 | foreach ($aArray as $aMessage) { 125 | $sHtml .= $this->render($aMessage); 126 | } 127 | 128 | $template->add('listeners',$sHtml); 129 | 130 | $this->clear(); 131 | 132 | } 133 | 134 | } -------------------------------------------------------------------------------- /website/classes/Listeners/Message.php: -------------------------------------------------------------------------------- 1 | set(null); 57 | } 58 | 59 | /** 60 | * Wstawienie komunikatu do kolejki 61 | * @param string $sType success/info/warning/error 62 | * @param string $sMessage 63 | */ 64 | public function push($sType, $sMessage) { 65 | $aArray = $this->get(); 66 | 67 | if (empty($aArray)) { 68 | $aArray = array(); 69 | } 70 | 71 | array_push($aArray, array('type'=>$sType,'message'=>$sMessage)); 72 | $this->set($aArray); 73 | } 74 | 75 | /** 76 | * Utworzenie kodu HTML z wiadomością 77 | * @param array $aMessage 78 | * @return string 79 | */ 80 | // private function render(array $aMessage) { 81 | // 82 | // 83 | // switch ($aMessage['type']) { 84 | // 85 | // case 'success': 86 | // $sClass = 'alert alert-success'; 87 | // break; 88 | // 89 | // case 'info': 90 | // $sClass = 'alert alert-info'; 91 | // break; 92 | // 93 | // case 'error': 94 | // $sClass = 'alert alert-error'; 95 | // break; 96 | // 97 | // default: 98 | // $sClass = 'alert'; 99 | // break; 100 | // 101 | // } 102 | // 103 | // $sHtml = '
'.$aMessage['message'].'
'; 104 | // 105 | // return $sHtml; 106 | // } 107 | 108 | /** 109 | * Rejestracja listenera 110 | * @param array $aParams 111 | * @param \General\Templater $template 112 | */ 113 | public function register(array &$aParams, \General\Templater $template) { 114 | 115 | $aArray = $this->get(); 116 | 117 | if (empty($aArray)) { 118 | return; 119 | } 120 | 121 | $sHtml = ''; 122 | 123 | foreach ($aArray as $aMessage) { 124 | //$sHtml .= $this->render($aMessage); 125 | $sHtml .= LowLevelMessage::getInstance()->push($aMessage['type'], $aMessage['message']); 126 | 127 | } 128 | 129 | //$template->add('listeners',$sHtml); 130 | 131 | $this->clear(); 132 | 133 | } 134 | 135 | } -------------------------------------------------------------------------------- /website/classes/Controller/Main.php: -------------------------------------------------------------------------------- 1 | quoteAll($aRequest); 57 | 58 | /** 59 | * Inicjacja szablonu 60 | * @var \General\Templater 61 | */ 62 | $template = new \General\Templater('index.html'); 63 | 64 | /* 65 | * Rejestracja listenerów 66 | */ 67 | \Listeners\Message::getInstance()->register($aRequest, $template); 68 | 69 | if (empty ( $aRequest ['class'] )) { 70 | $aRequest ['class'] = 'Frontpage'; 71 | } 72 | 73 | if (empty ( $aRequest ['method'] )) { 74 | $aRequest ['method'] = 'render'; 75 | } 76 | 77 | if (! isset ( $HTTP_RAW_POST_DATA )) { 78 | $HTTP_RAW_POST_DATA = file_get_contents ( "php://input" ); 79 | } 80 | 81 | $retVal = ''; 82 | 83 | $className = ''; 84 | switch ($aRequest ['class']) { 85 | 86 | default: 87 | $className = '\\Controller\\'.$aRequest ['class']; 88 | break; 89 | } 90 | 91 | 92 | $methodName = ''; 93 | switch ($aRequest ['method']) { 94 | 95 | default : 96 | $methodName = $aRequest ['method']; 97 | break; 98 | 99 | } 100 | 101 | 102 | if (class_exists($className)) { 103 | 104 | $tObject = $className::getInstance(); 105 | 106 | if (method_exists($tObject, $methodName)) { 107 | $tObject->{$methodName}($aRequest, $template); 108 | } 109 | } 110 | 111 | \Listeners\LowLevelMessage::getInstance()->register($aRequest, $template); 112 | 113 | } 114 | catch ( CustomException $e ) { 115 | $template->add('mainContent',\General\Debug::cThrow ( $e->getMessage (), $e, array ('send' => false, 'display' => false ) )); 116 | } 117 | catch ( Exception $e ) { 118 | $template->add('mainContent',\General\Debug::cThrow ( null, $e )); 119 | } 120 | 121 | $template->add('chartHead', ''); 122 | $template->add('listeners', ''); 123 | $template->add('menu', ''); 124 | $template->add('mainContent', ''); 125 | $template->add('titleSecond', ''); 126 | $template->add('pageTitle', '{T:Product Name}'); 127 | 128 | return (string) $template; 129 | 130 | } 131 | 132 | } -------------------------------------------------------------------------------- /sensor_driver.c: -------------------------------------------------------------------------------- 1 | /* 2 | Based on Adafruit DHT Driver 3 | https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code/tree/master/Adafruit_DHT_Driver 4 | 5 | Paweł Spychalski 6 | pawel@spychalski.info 7 | http://www.spychalski.info 8 | 9 | */ 10 | 11 | #define BCM2708_PERI_BASE 0x20000000 12 | #define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */ 13 | 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #define MAXTIMINGS 100 30 | 31 | //#define DEBUG 32 | 33 | #define DHT11 11 34 | #define DHT22 22 35 | #define AM2302 22 36 | 37 | int readDHT(int type, int pin); 38 | 39 | int main(int argc, char **argv) 40 | { 41 | if (!bcm2835_init()) 42 | return 1; 43 | 44 | if (argc != 3) { 45 | printf("usage: %s [11|22|2302] GPIOpin#\n", argv[0]); 46 | printf("example: %s 2302 4 - Read from an AM2302 connected to GPIO #4\n", argv[0]); 47 | return 2; 48 | } 49 | int type = 0; 50 | if (strcmp(argv[1], "11") == 0) type = DHT11; 51 | if (strcmp(argv[1], "22") == 0) type = DHT22; 52 | if (strcmp(argv[1], "2302") == 0) type = AM2302; 53 | if (type == 0) { 54 | printf("Select 11, 22, 2302 as type!\n"); 55 | return 3; 56 | } 57 | 58 | int dhtpin = atoi(argv[2]); 59 | 60 | if (dhtpin <= 0) { 61 | printf("Please select a valid GPIO pin #\n"); 62 | return 3; 63 | } 64 | 65 | readDHT(type, dhtpin); 66 | return 0; 67 | 68 | } // main 69 | 70 | 71 | int bits[250], data[100]; 72 | int bitidx = 0; 73 | 74 | int readDHT(int type, int pin) { 75 | int counter = 0; 76 | int laststate = HIGH; 77 | int j=0; 78 | 79 | // Set GPIO pin to output 80 | bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP); 81 | 82 | bcm2835_gpio_write(pin, HIGH); 83 | usleep(500000); // 500 ms 84 | bcm2835_gpio_write(pin, LOW); 85 | usleep(20000); 86 | 87 | bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_INPT); 88 | 89 | data[0] = data[1] = data[2] = data[3] = data[4] = 0; 90 | 91 | // wait for pin to drop? 92 | while (bcm2835_gpio_lev(pin) == 1) { 93 | usleep(1); 94 | } 95 | 96 | // read data! 97 | for (int i=0; i< MAXTIMINGS; i++) { 98 | counter = 0; 99 | while ( bcm2835_gpio_lev(pin) == laststate) { 100 | counter++; 101 | //nanosleep(1); // overclocking might change this? 102 | if (counter == 1000) 103 | break; 104 | } 105 | laststate = bcm2835_gpio_lev(pin); 106 | if (counter == 1000) break; 107 | bits[bitidx++] = counter; 108 | 109 | if ((i>3) && (i%2 == 0)) { 110 | // shove each bit into the storage bytes 111 | data[j/8] <<= 1; 112 | if (counter > 200) 113 | data[j/8] |= 1; 114 | j++; 115 | } 116 | } 117 | 118 | if ((j >= 39) && 119 | (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) { 120 | 121 | if (type == DHT11) { 122 | printf("%d|%d", data[0], data[2]); 123 | } 124 | 125 | if (type == DHT22) { 126 | 127 | float f, h; 128 | h = data[0] * 256 + data[1]; 129 | h /= 10; 130 | 131 | f = (data[2] & 0x7F)* 256 + data[3]; 132 | f /= 10.0; 133 | if (data[2] & 0x80) f *= -1; 134 | 135 | printf("%.1f|%.1f", h, f); 136 | 137 | } 138 | 139 | return 1; 140 | }else { 141 | printf("|"); 142 | } 143 | 144 | return 0; 145 | } 146 | -------------------------------------------------------------------------------- /website/classes/Cache/Memcached.php: -------------------------------------------------------------------------------- 1 | Singleton 35 | */ 36 | private static $instance; 37 | 38 | /** 39 | * Konstruktor statyczny 40 | */ 41 | public static function getInstance(){ 42 | if (empty(self::$instance)) { 43 | $className = __CLASS__; 44 | self::$instance = new $className; 45 | } 46 | return self::$instance; 47 | } 48 | 49 | /** 50 | * Cache wewnętrzny do współpracy check-get 51 | * @var array 52 | */ 53 | private $internalCache = array(); 54 | 55 | static public $host = '192.168.2.99'; 56 | static public $port = 11211; 57 | 58 | /** 59 | * Konstruktor 60 | */ 61 | private function __construct() { 62 | $this->memcached = new \Memcache(); 63 | $this->memcached->connect(self::$host, self::$port); 64 | } 65 | 66 | /** 67 | * Sprawdzenie, czy w cache znajduje się wpis 68 | * 69 | * @param string $module 70 | * @param string $property 71 | * @return boolean 72 | */ 73 | function check($module, $property) { 74 | 75 | $tValue = $this->get($module, $property); 76 | 77 | if ($tValue === false) { 78 | return false; 79 | }else { 80 | return true; 81 | } 82 | 83 | } 84 | 85 | /** 86 | * Pobranie wartości z cache 87 | * 88 | * @param string $module 89 | * @param string $property 90 | * @return mixed 91 | */ 92 | function get($module, $property) { 93 | 94 | $tKey = $this->getKey($module, $property); 95 | 96 | if (!isset($this->internalCache[$tKey])) { 97 | $this->internalCache[$tKey] = $this->memcached->get($tKey); 98 | } 99 | 100 | return $this->internalCache[$tKey]; 101 | } 102 | 103 | /** 104 | * Wyczyszczenie konkretnego wpisu w cache 105 | * 106 | * @param string $module 107 | * @param string $property 108 | */ 109 | function clear($module, $property = null) { 110 | $this->memcached->delete($this->getKey($module, $property)); 111 | } 112 | 113 | /** 114 | * Wyczyszczenie konkretnego modułu cache 115 | * 116 | * @param string $module 117 | */ 118 | function clearModule($module = null) { 119 | 120 | $this->memcached->flush(); 121 | 122 | } 123 | 124 | /** 125 | * Wstawienei do cache 126 | * 127 | * @param string $module 128 | * @param string $property 129 | * @param mixed $value 130 | * @param int $sessionLength 131 | */ 132 | function set($module, $property, $value, $sessionLength = null) { 133 | 134 | if ($sessionLength == null) { 135 | $sessionLength = $this->timeThreshold; 136 | } 137 | 138 | $this->memcached->set($this->getKey($module, $property), $value, $this->useZip, $sessionLength); 139 | } 140 | 141 | /** 142 | * Wyczyszczenie wpisów zależnych od podanej klasy 143 | * 144 | * @param string $className 145 | */ 146 | public function clearClassCache($className = null) { 147 | 148 | $this->memcached->flush(); 149 | } 150 | 151 | /** 152 | * Oczyszczenie całego cache 153 | */ 154 | public function clearAll() { 155 | $this->memcached->flush(); 156 | } 157 | 158 | /** 159 | * Zestawienie klucza 160 | * @param string $module 161 | * @param string $property 162 | * @return string 163 | */ 164 | private function getKey($module, $property) { 165 | return $module.'::'.$property; 166 | } 167 | 168 | /** 169 | * Pobranie statystyk memcached 170 | * @return array 171 | */ 172 | public function getStatistics() { 173 | return $this->memcached->getStats(); 174 | } 175 | 176 | } -------------------------------------------------------------------------------- /website/classes/Cache/Session.php: -------------------------------------------------------------------------------- 1 | Singleton 20 | */ 21 | private static $instance; 22 | 23 | /** 24 | * Konstruktor statyczny 25 | * @deprecated 26 | */ 27 | public static function getInstance(){ 28 | if (empty(self::$instance)) { 29 | $className = __CLASS__; 30 | self::$instance = new $className; 31 | } 32 | return self::$instance; 33 | } 34 | 35 | /** 36 | * Czyszczenie cache z przeterminowanych wpisów 37 | * 38 | * @param string $module 39 | * @return boolean 40 | */ 41 | private function maintenace($module) { 42 | 43 | if (! isset ( $_SESSION [$this->cacheName] [$module] )) 44 | return false; 45 | 46 | //Sprawdz, czy wykonać czyszczenie 47 | if (time () < $_SESSION [$this->cacheMaintenanceTimeName] [$module]) 48 | return false; 49 | 50 | //Ustaw czas następnego czyszczenia 51 | $_SESSION [$this->cacheMaintenanceTimeName] [$module] = time () + $this->timeThreshold; 52 | 53 | //Pobierz wszystkie klucze w module 54 | $keys = array_keys ( $_SESSION [$this->cacheName] [$module] ); 55 | 56 | //Wykonaj pętlę po kluczach 57 | foreach ( $keys as $value ) { 58 | //Oczyść przeterminowane klucze 59 | if (time () > $_SESSION [$this->cacheName] [$module] [$value] ['time']) { 60 | unset ( $_SESSION [$this->cacheName] [$module] [$value] ); 61 | } 62 | } 63 | 64 | return true; 65 | } 66 | 67 | /** 68 | * @return int 69 | */ 70 | public function getTimeThreshold() { 71 | return $this->timeThreshold; 72 | } 73 | 74 | /** 75 | * @param int $timeThreshold 76 | */ 77 | public function setTimeThreshold($timeThreshold) { 78 | $this->timeThreshold = $timeThreshold; 79 | } 80 | 81 | /** 82 | * Konstruktor 83 | * 84 | * @param int $size - rozmiar cache 85 | * @return boolean 86 | */ 87 | private function __construct($size = 100) { 88 | $this->size = $size; 89 | 90 | return true; 91 | } 92 | 93 | /** 94 | * Sprawdzenie, czy jest wpis w cache 95 | * 96 | * @param string $module 97 | * @param string $id 98 | * @return boolean 99 | */ 100 | function check($module, $id) { 101 | if (isset ( $_SESSION [$this->cacheName] [$module] [$id] )) { 102 | return true; 103 | } elseif (isset ( $this->table [$module] [$id] )) { 104 | return true; 105 | } else { 106 | return false; 107 | } 108 | } 109 | 110 | /** 111 | * Pobranie pozycji z cache 112 | * 113 | * @param string $module 114 | * @param string $id 115 | * @return cache 116 | */ 117 | function get($module, $id) { 118 | if (isset ( $_SESSION [$this->cacheName] [$module] [$id] )) { 119 | 120 | $tValue = $_SESSION [$this->cacheName] [$module] [$id] ['value']; 121 | 122 | $this->maintenace ( $module ); 123 | 124 | return $tValue; 125 | } elseif (isset ( $this->table [$module] [$id] )) { 126 | return $this->table [$module] [$id]; 127 | } else { 128 | return NULL; 129 | } 130 | } 131 | 132 | /** 133 | * Wstawienie do cache 134 | * 135 | * @param string $module 136 | * @param string $id 137 | * @param string $value 138 | * @param boolean $useSession 139 | * @return string 140 | */ 141 | function set($module, $id, $value, $useSession = false, $expire = null) { 142 | if ($useSession) { 143 | //Zapisz w sesji 144 | if ($expire == null) 145 | $expire = $this->timeThreshold; 146 | $_SESSION [$this->cacheName] [$module] [$id] ['value'] = $value; 147 | $_SESSION [$this->cacheName] [$module] [$id] ['time'] = time () + $expire; 148 | 149 | /* 150 | * Określ czas następnego czyszczenia cache dla tego modułu 151 | */ 152 | if (! isset ( $_SESSION [$this->cacheMaintenanceTimeName] [$module] )) { 153 | $_SESSION [$this->cacheMaintenanceTimeName] [$module] = time () + $this->timeThreshold; 154 | } 155 | 156 | } else { 157 | //Zapisz w tablicy zwykłej 158 | $this->table [$module] [$id] = $value; 159 | } 160 | $this->currentSize += 1; 161 | return true; 162 | } 163 | 164 | /** 165 | * Czyszczenie pozycji cache 166 | * 167 | * @param string $module 168 | * @param string $id 169 | */ 170 | function clear($module, $id = null) { 171 | if ($id != null) { 172 | unset ( $_SESSION [$this->cacheName] [$module] [$id] ); 173 | unset ( $this->table [$module] [$id] ); 174 | } else { 175 | unset ( $_SESSION [$this->cacheName] [$module] ); 176 | unset ( $this->table [$module] ); 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /website/classes/General/Templater.php: -------------------------------------------------------------------------------- 1 | fileName = dirname(__FILE__) . '/../../templates/' . $fileName; 50 | $this->load(); 51 | 52 | $this->translation = $translation; 53 | 54 | if (empty($this->translation)) { 55 | $this->translation = Translate::getDefault(); 56 | } 57 | 58 | return true; 59 | } 60 | 61 | /** 62 | * Template load 63 | * 64 | */ 65 | private function load() 66 | { 67 | 68 | $module = 'Templater::load'; 69 | $property = md5(realpath('') . '|' . $this->fileName); 70 | 71 | if (!self::$useCache || !Cache::getInstance()->check($module, $property)) { 72 | 73 | try { 74 | if (file_exists($this->fileName)) { 75 | 76 | $tFile = fopen($this->fileName, 'r'); 77 | 78 | flock($tFile, LOCK_SH); 79 | 80 | $this->template = fread($tFile, filesize($this->fileName)); 81 | 82 | flock($tFile, LOCK_UN); 83 | fclose($tFile); 84 | 85 | Cache::getInstance()->set($module, $property, $this->template, 86400); 86 | } 87 | else { 88 | throw new \Exception('Brak pliku w ścieżce: "' . $this->fileName . '"'); 89 | } 90 | } catch (Exception $e) { 91 | throw new \Exception('Błąd otwarcia szablonu'); 92 | } 93 | } 94 | else { 95 | $this->template = Cache::getInstance()->get($module, $property); 96 | } 97 | } 98 | 99 | /** 100 | * Template reload 101 | * 102 | */ 103 | public function reset() 104 | { 105 | 106 | $this->load(); 107 | } 108 | 109 | /** 110 | * Adding new position to template 111 | * 112 | * @param mixed $key 113 | * @param string $value 114 | * @return boolean 115 | */ 116 | public function add($key, $value = null) 117 | { 118 | 119 | try { 120 | 121 | if (!is_array($key) && !is_object($key)) { 122 | $this->template = str_replace('{' . $key . '}', $value, $this->template); 123 | } 124 | else { 125 | foreach ($key as $tKey => $tValue) { 126 | 127 | if ($tValue === NULL) { 128 | $tValue = ''; 129 | } 130 | 131 | $this->add($tKey, $tValue); 132 | } 133 | } 134 | } catch (Exception $e) { 135 | return false; 136 | } 137 | 138 | return true; 139 | } 140 | 141 | /** 142 | * Conditional block removal 143 | * 144 | * @param string $key 145 | */ 146 | public function remove($key) 147 | { 148 | 149 | $this->template = preg_replace('!({C:' . $key . '}.*{/C:' . $key . '})!ms', '', $this->template); 150 | } 151 | 152 | /** 153 | * Template render 154 | * 155 | * @return string 156 | */ 157 | public function get() 158 | { 159 | 160 | $this->template = preg_replace_callback('!({T:[^}]*})!', array($this, 'translationReplacer'), $this->template); 161 | 162 | $this->template = preg_replace('!({C:[^}]*})!', '', $this->template); 163 | $this->template = preg_replace('!({/C:[^}]*})!', '', $this->template); 164 | 165 | return $this->template; 166 | } 167 | 168 | /** 169 | * Template translation parsing 170 | * 171 | * @param array $matches 172 | * @return string 173 | */ 174 | private function translationReplacer($matches) 175 | { 176 | 177 | $retval = $matches [1]; 178 | $retval = mb_substr($retval, 3, - 1); 179 | 180 | $retval = $this->translation->get($retval); 181 | 182 | return $retval; 183 | } 184 | 185 | /** 186 | * __toString magic function 187 | * 188 | * @return string 189 | */ 190 | public function __toString() 191 | { 192 | 193 | return $this->get(); 194 | } 195 | 196 | } -------------------------------------------------------------------------------- /website/classes/General/Formater.php: -------------------------------------------------------------------------------- 1 | $len) { 16 | $str = substr($text,0,$len); 17 | $str .="..."; 18 | 19 | if($link!=null){ 20 | $str .=' więcej'; 21 | } 22 | 23 | 24 | return $str; 25 | } 26 | else return $text; 27 | } 28 | 29 | /** 30 | * Obliczenie procentów wartości max. 31 | * 32 | * @param numeric $value 33 | * @param numeric $max 34 | * @return int 35 | */ 36 | static public function getPercentage($value, $max) 37 | { 38 | 39 | if (empty($max)) { 40 | return 0; 41 | } 42 | 43 | return round((100 / $max) * $value); 44 | } 45 | 46 | /** 47 | * Funkcja formatująca datę do postaci YYYY-MM-DD 48 | * @param $date 49 | * @return sformatowana data 50 | */ 51 | static public function formatDate($date) 52 | { 53 | 54 | if (!is_numeric($date)) { 55 | $date = strtotime($date); 56 | } 57 | 58 | $retVal = date("Y-m-d", $date); 59 | return $retVal; 60 | } 61 | 62 | static function getmicrotime() 63 | { 64 | list ( $usec, $sec ) = explode(" ", microtime()); 65 | return ((float) $usec + (float) $sec); 66 | } 67 | 68 | /** 69 | * Funkcja formatująca datę do postaci YYYY-MM-DD HH:ii 70 | * @param $date 71 | * @return sformatowana data 72 | */ 73 | static public function formatDateTime($date) 74 | { 75 | 76 | if (!is_numeric($date)) { 77 | $date = strtotime($date); 78 | } 79 | 80 | $retVal = date("Y-m-d H:i", $date); 81 | if ($retVal == '1970-01-01 01:00') { 82 | $retVal = null; 83 | } 84 | return $retVal; 85 | } 86 | 87 | /** 88 | * Funkcja formatująca datę do postaci HH-ii 89 | * @param $date 90 | * @return sformatowana data 91 | */ 92 | static public function formatTime($date) 93 | { 94 | 95 | $retVal = date("H:i", strtotime($date)); 96 | return $retVal; 97 | } 98 | 99 | /** 100 | * Funkcja zwaracająca datę w postaci YYYY-MM-DD z UNIX Timestam 101 | * @param $date 102 | * @return sformatowana data 103 | */ 104 | function getDate($date) 105 | { 106 | 107 | $retVal = date("Y-m-d", $date); 108 | return $retVal; 109 | } 110 | 111 | /** 112 | * Funkcja formatująca wartość do postaci xxx xxx,xx 113 | * @param $value 114 | * @param $unit jednostka wartości 115 | * @return sformatowana wartość 116 | */ 117 | static public function formatValue($value, $unit = "") 118 | { 119 | 120 | if ($value === null) { 121 | return ''; 122 | } 123 | 124 | if (empty($value)) { 125 | $value = 0; 126 | } 127 | 128 | $value = str_replace(",", ".", $value); 129 | 130 | $retVal = number_format($value, 2, ",", " ") . " " . $unit; 131 | return $retVal; 132 | } 133 | 134 | static public function formatInt($value, $unit = "") 135 | { 136 | 137 | $retVal = number_format($value, 0, ",", " ") . " " . $unit; 138 | return $retVal; 139 | } 140 | 141 | static public function formatFloat($value, $decimal) { 142 | $retVal = number_format($value, $decimal, ",", " "); 143 | return $retVal; 144 | } 145 | 146 | /** 147 | * Formatuje liczbę 148 | * 149 | * @param int $value 150 | * @return string 151 | */ 152 | function formatCount($value) 153 | { 154 | 155 | $retVal = number_format($value, 0, "", " "); 156 | return $retVal; 157 | } 158 | 159 | /** 160 | * 161 | * Pełny trim ze wszystkimi wielokrotynymi spacjami 162 | * @param string $str 163 | * @return string 164 | */ 165 | static public function superTrim($str) 166 | { 167 | 168 | $char = "\n"; 169 | while (true) { 170 | if (substr($str, - (strlen($char))) == $char) { 171 | $str = substr($str, 0, - (strlen($char))); 172 | } 173 | else { 174 | break; 175 | } 176 | 177 | return trim($str); 178 | } 179 | } 180 | 181 | /** 182 | * Zamiana bool na ciąg Tak/Nie 183 | * @param boolean $in 184 | * @return string 185 | */ 186 | static public function parseYesNo($in) 187 | { 188 | 189 | if (empty($in)) { 190 | return \Translate\Controller::getDefault()->get('Nie'); 191 | } 192 | else { 193 | return \Translate\Controller::getDefault()->get('Tak'); 194 | } 195 | } 196 | 197 | } 198 | -------------------------------------------------------------------------------- /website/classes/Database/SQLiteWrapper.php: -------------------------------------------------------------------------------- 1 | 9 | * @link http://www.spychalski.info 10 | * @version 0.1 11 | * @copyright 2009 Lynx-IT Pawel Stanislaw Spychalski 12 | * 13 | */ 14 | class SQLiteWrapper { 15 | 16 | 17 | /** 18 | * @var \SQLite3 19 | */ 20 | protected $dbHandle = null; 21 | 22 | /** 23 | * @var Config 24 | */ 25 | protected $dbConfig; 26 | 27 | protected $queryCount = 0; 28 | 29 | /** 30 | * Czy zapisywać każde zapytanie do logu 31 | * 32 | * @var boolean 33 | */ 34 | public $writeToFile = false; 35 | 36 | protected $logFile = null; 37 | 38 | protected function openLogFile() { 39 | if (empty ( $this->logFile )) { 40 | $this->logFile = fopen ( 'db.log', 'a' ); 41 | } 42 | } 43 | 44 | protected function writeLog($query) { 45 | $this->openLogFile (); 46 | fputs ( $this->logFile, $query . "\n" ); 47 | } 48 | 49 | protected function closeLogFile() { 50 | if (! empty ( $this->logFile )) { 51 | fclose ( $this->logFile ); 52 | } 53 | } 54 | 55 | /** 56 | * @return int 57 | */ 58 | public function getQueryCount() { 59 | return $this->queryCount; 60 | } 61 | 62 | /** 63 | * Czy nastąpiło połączenie do bazy danych 64 | * 65 | * @var boolean 66 | */ 67 | protected $connected = false; 68 | 69 | public function quote($string) { 70 | 71 | if (! $this->connected) { 72 | $this->connect (); 73 | } 74 | 75 | return $this->dbHandle->escapeString($string); 76 | } 77 | 78 | /** 79 | * Zaquotowanie wszystkich pól 80 | * @param array/stdClass $data 81 | */ 82 | public function quoteAll(&$data) { 83 | 84 | if (is_array($data)) { 85 | 86 | foreach ($data as $tKey => $tValue) { 87 | 88 | if (is_array($tValue)) { 89 | foreach($tValue as $tKey2=>$tValue2) { 90 | $data[$tKey][$tKey2] = $this->quote($tValue2); 91 | } 92 | } 93 | else { 94 | $data[$tKey] = $this->quote($tValue); 95 | } 96 | } 97 | 98 | }elseif(is_object($data)) { 99 | 100 | foreach ($data as $tKey => $tValue) { 101 | $data->{$tKey} = $this->quote($tValue); 102 | } 103 | 104 | } 105 | 106 | } 107 | 108 | public function lastUsedID() { 109 | 110 | return $this->dbHandle->lastInsertRowID(); 111 | } 112 | 113 | /** 114 | * Wykonanie zapytania bazy danych 115 | * 116 | * @param string $query 117 | * @return resource 118 | * @throws Exception 119 | */ 120 | public function execute($query) { 121 | 122 | if (! $this->connected) { 123 | $this->connect (); 124 | } 125 | 126 | if ($this->dbHandle == null) { 127 | return false; 128 | } 129 | $this->queryCount += 1; 130 | 131 | $tResult = $this->dbHandle->query($query); 132 | if (! $tResult) { 133 | throw new Exception ( $this->dbHandle->lastErrorMsg(), $this->dbHandle->lastErrorCode() ); 134 | } 135 | 136 | /** 137 | * logowanie zapytań do pliku 138 | */ 139 | if ($this->writeToFile) { 140 | $this->writeLog ( $query ); 141 | } 142 | 143 | return $tResult; 144 | } 145 | 146 | public function fetch(\SQLite3Result $result = null) { 147 | 148 | if ($this->dbHandle == null) { 149 | return false; 150 | } 151 | 152 | $aTemp = $result->fetchArray(SQLITE3_ASSOC); 153 | 154 | if (!empty($aTemp)) { 155 | $tResult = new \stdClass(); 156 | foreach($aTemp as $sKey => $mValue) { 157 | $tResult->{$sKey} = $mValue; 158 | } 159 | }else { 160 | $tResult = false; 161 | } 162 | 163 | unset($aTemp); 164 | 165 | return $tResult; 166 | } 167 | 168 | public function fetchAssoc(\SQLite3Result $result = null) { 169 | 170 | if ($this->dbHandle == null) { 171 | return false; 172 | } 173 | return $result->fetchArray(SQLITE3_ASSOC); 174 | } 175 | 176 | public function connect() { 177 | 178 | try { 179 | 180 | $this->dbHandle = new \SQLite3($this->dbConfig ['db']); 181 | ; 182 | if (empty ( $this->dbHandle )) { 183 | throw new Exception ( 'No connection' ); 184 | } 185 | 186 | $this->connected = true; 187 | $this->dbConfig ['handle'] = $this->dbHandle; 188 | 189 | } catch ( Exception $e ) { 190 | \psDebug::halt ( 'Brak połączenia z bazą danych', $e, array ('display' => false ) ); 191 | } 192 | } 193 | 194 | /** 195 | * Konstruktor bazy danych 196 | * 197 | * @param Config 198 | * @return boolean 199 | */ 200 | public function __construct(Config $dbConfig) { 201 | 202 | $this->dbConfig = $dbConfig; 203 | return true; 204 | } 205 | 206 | public function __destruct() { 207 | 208 | $this->closeLogFile (); 209 | $this->close(); 210 | 211 | } 212 | 213 | /** 214 | * Pobranie uchwytu do bazy danych 215 | * 216 | * @return resource 217 | */ 218 | public function getHandle() { 219 | 220 | if ($this->dbHandle == null) { 221 | return false; 222 | } 223 | return $this->dbHandle; 224 | } 225 | 226 | /** 227 | * Zamknięcie połączenia z bazą danych 228 | * 229 | */ 230 | public function close() { 231 | if (! empty ( $this->dbHandle )) { 232 | $this->dbHandle->close(); 233 | } 234 | return true; 235 | } 236 | 237 | } 238 | 239 | class Exception extends \Exception { 240 | 241 | } -------------------------------------------------------------------------------- /website/classes/Model/Readout.php: -------------------------------------------------------------------------------- 1 | execute("SELECT AVG(Temperature) Temperature, AVG(Humidity) Humidity FROM {$this->tableName} WHERE Date>='{$stamp}'"); 42 | 43 | return $db->fetch($rResult); 44 | 45 | } 46 | 47 | public function getMin($days = 1) { 48 | 49 | $db = \Database\Factory::getInstance(); 50 | 51 | $stamp = date('Y-m-d H:i',strtotime ( "-{$days} day" , time() ) ); 52 | 53 | $rResult = $db->execute("SELECT MIN(Temperature) Temperature, MIN(Humidity) Humidity FROM {$this->tableName} WHERE Date>='{$stamp}'"); 54 | 55 | return $db->fetch($rResult); 56 | 57 | } 58 | 59 | public function getMax($days = 1) { 60 | 61 | $db = \Database\Factory::getInstance(); 62 | 63 | $stamp = date('Y-m-d H:i',strtotime ( "-{$days} day" , time() ) ); 64 | 65 | $rResult = $db->execute("SELECT MAX(Temperature) Temperature, MAX(Humidity) Humidity FROM {$this->tableName} WHERE Date>='{$stamp}'"); 66 | 67 | return $db->fetch($rResult); 68 | 69 | } 70 | 71 | public function getCurrent() { 72 | 73 | $db = \Database\Factory::getInstance(); 74 | 75 | $rResult = $db->execute("SELECT * FROM {$this->tableName} ORDER BY `Date` DESC LIMIT 1"); 76 | 77 | return $db->fetch($rResult); 78 | 79 | } 80 | 81 | public function getHistory($skip = 0, $limit = 25) { 82 | $retVal = array(); 83 | 84 | $cache = \Cache\Factory::getInstance(); 85 | 86 | $sModule = get_class($this).'::getHistory'; 87 | $sProperty = $skip.'|'.$limit; 88 | 89 | if (!$cache->check($sModule, $sProperty)) { 90 | 91 | $db = \Database\Factory::getInstance(); 92 | 93 | $rResult = $db->execute("SELECT * FROM {$this->tableName} ORDER BY `Date` DESC LIMIT {$limit} OFFSET {$skip}"); 94 | 95 | while ($tResult = $db->fetchAssoc($rResult)) { 96 | array_push($retVal, $tResult); 97 | } 98 | 99 | $cache->set($sModule, $sProperty, $retVal, 300); 100 | 101 | }else { 102 | $retVal = $cache->get($sModule, $sProperty); 103 | } 104 | 105 | return $retVal; 106 | 107 | } 108 | 109 | public function getDayAggregate($days = 7, $orderBy = "DESC") { 110 | $retVal = array(); 111 | 112 | $cache = \Cache\Factory::getInstance(); 113 | 114 | $sModule = get_class($this).'::getDayAggregate'; 115 | $sProperty = $days.'|'.$orderBy; 116 | 117 | if (!$cache->check($sModule, $sProperty)) { 118 | 119 | $db = \Database\Factory::getInstance(); 120 | 121 | $rResult = $db->execute("select 122 | date(`Date`) Date, AVG(Temperature) Temperature 123 | , AVG(Humidity) Humidity 124 | , MIN(Temperature) MinTemperature 125 | , MAX(Temperature) MaxTemperature 126 | , MIN(Humidity) MinHumidity 127 | , MAX(Humidity) MaxHumidity 128 | FROM 129 | {$this->tableName} 130 | where 131 | `Date`>(SELECT DATETIME('now', '-{$days} day')) 132 | group by 133 | date(`Date`) 134 | ORDER BY 135 | date(`Date`) {$orderBy} 136 | "); 137 | 138 | while ($tResult = $db->fetchAssoc($rResult)) { 139 | array_push($retVal, $tResult); 140 | } 141 | 142 | $cache->set($sModule, $sProperty, $retVal, 3600); 143 | 144 | }else { 145 | $retVal = $cache->get($sModule, $sProperty); 146 | } 147 | 148 | return $retVal; 149 | 150 | } 151 | 152 | public function getHourAggregate($hours = 24, $orderBy = "DESC") { 153 | $retVal = array(); 154 | 155 | $cache = \Cache\Factory::getInstance(); 156 | 157 | $sModule = get_class($this).'::getHourAggregate'; 158 | $sProperty = $hours.'|'.$orderBy; 159 | 160 | if (!$cache->check($sModule, $sProperty)) { 161 | 162 | $db = \Database\Factory::getInstance(); 163 | 164 | $rResult = $db->execute("select 165 | strftime('%Y-%m-%d %H:00:00', `Date`) Date 166 | , AVG(Temperature) Temperature 167 | , AVG(Humidity) Humidity 168 | , MIN(Temperature) MinTemperature 169 | , MAX(Temperature) MaxTemperature 170 | , MIN(Humidity) MinHumidity 171 | , MAX(Humidity) MaxHumidity 172 | FROM 173 | {$this->tableName} 174 | where 175 | datetime(`Date`)>(SELECT DATETIME('now', '-{$hours} hour')) 176 | group by 177 | strftime('%Y-%m-%d %H:00:00', `Date`) 178 | ORDER BY 179 | datetime(`Date`) {$orderBy} 180 | "); 181 | 182 | while ($tResult = $db->fetchAssoc($rResult)) { 183 | array_push($retVal, $tResult); 184 | } 185 | 186 | $cache->set($sModule, $sProperty, $retVal, 3600); 187 | 188 | }else { 189 | $retVal = $cache->get($sModule, $sProperty); 190 | } 191 | 192 | return $retVal; 193 | 194 | } 195 | 196 | } -------------------------------------------------------------------------------- /website/classes/Cache/Apc.php: -------------------------------------------------------------------------------- 1 | Singleton 34 | * @var \Cache\Apc 35 | */ 36 | private static $instance; 37 | 38 | /** 39 | * Wewnętrzny cache klasy 40 | * @var array 41 | */ 42 | private $internalCache = Array(); 43 | 44 | /** 45 | * Konstruktor statyczny 46 | * @return \Cache\Apc 47 | */ 48 | public static function getInstance(){ 49 | if (empty(self::$instance)) { 50 | $className = __CLASS__; 51 | self::$instance = new $className; 52 | } 53 | return self::$instance; 54 | } 55 | 56 | /** 57 | * Ustawienie prefixu na nazwy klucza 58 | * @param string $prefix 59 | */ 60 | static public function sSetPrefix($prefix) { 61 | self::$sCachePrefix = $prefix; 62 | } 63 | 64 | /** 65 | * Konstruktor prywatny 66 | */ 67 | private function __construct() { 68 | if (time() - $this->getGcRunTime() > self::$gcTimeThreshold) { 69 | $this->setGcRunTime(); 70 | $this->garbageCollector(); 71 | } 72 | } 73 | 74 | /** 75 | * Poprawnie prefixu nazw klucza 76 | * @return string 77 | */ 78 | static public function sGetPrefix() { 79 | return self::$sCachePrefix; 80 | } 81 | 82 | /** 83 | * Domyślny czas ważności cache [s] 84 | * 85 | * @var int 86 | */ 87 | private $timeThreshold = 7200; 88 | 89 | /** 90 | * Sprawdzenie, czy w cache znajduje się wpis 91 | * @param string $module 92 | * @param string $property 93 | * @return boolean 94 | */ 95 | public function check($module, $property) { 96 | 97 | $tValue = $this->get($module, $property); 98 | 99 | if ($tValue === false) { 100 | return false; 101 | }else { 102 | return true; 103 | } 104 | } 105 | 106 | /** 107 | * Pobranie wartości z cache 108 | * @param string $module 109 | * @param string $property 110 | * @return mixed 111 | */ 112 | public function get($module, $property) { 113 | 114 | $key = $this->getKey($module, $property); 115 | 116 | if (isset($this->internalCache[$key])) { 117 | $retVal = $this->internalCache[$key]; 118 | }else { 119 | $retVal = apc_fetch($key); 120 | $this->internalCache[$key] = $retVal; 121 | } 122 | 123 | return $retVal; 124 | } 125 | 126 | /** 127 | * Wyczyszczenie konkretnego wpisu w cache 128 | * 129 | * @param string $module 130 | * @param string $property 131 | */ 132 | public function clear($module, $property = null) { 133 | apc_delete($this->getKey($module, $property)); 134 | } 135 | 136 | /** 137 | * Wyczyszczenie konkretnego modułu cache 138 | * 139 | * @param string $module 140 | */ 141 | public function clearModule($module = null) { 142 | 143 | $iterator = new \APCIterator('user'); 144 | while ($iterator->current()) { 145 | 146 | $tKey = $iterator->key(); 147 | 148 | if (mb_strpos ( $tKey, $module . '||' ) !== false) { 149 | apc_delete($tKey); 150 | } 151 | $iterator->next(); 152 | } 153 | 154 | } 155 | 156 | /** 157 | * Wstawienei do cache 158 | * 159 | * @param string $module 160 | * @param string $property 161 | * @param mixed $value 162 | * @param int $sessionLength 163 | */ 164 | public function set($module, $property, $value, $sessionLength = null) { 165 | 166 | if ($sessionLength == null) { 167 | $sessionLength = $this->timeThreshold; 168 | } 169 | 170 | apc_store ( $this->getKey($module, $property) , $value , $sessionLength); 171 | } 172 | 173 | private function getGcRunTime() { 174 | 175 | $retVal = apc_fetch('CacheOverApcGcRunTime'); 176 | 177 | if ($retVal === false) { 178 | $retVal = 0; 179 | } 180 | 181 | return $retVal; 182 | } 183 | 184 | private function setGcRunTime() { 185 | @apc_store ( 'CacheOverApcGcRunTime' , time() , 86400); 186 | } 187 | 188 | public function runGarbageCollector() { 189 | $this->garbageCollector(); 190 | } 191 | 192 | /** 193 | * Garbage collector niszczący wpisy o dacie starszej niż zakładany okres 194 | */ 195 | private function garbageCollector() { 196 | $iterator = new \APCIterator('user'); 197 | while ($tKey = $iterator->current()) { 198 | 199 | if (time() - $tKey['ttl'] > $tKey[self::$gcMethod]) { 200 | apc_delete($tKey['key']); 201 | } 202 | 203 | $iterator->next(); 204 | } 205 | } 206 | 207 | /** 208 | * Wyczyszczenie wpisów zależnych od podanej klasy 209 | * 210 | * @param string $className 211 | */ 212 | public function clearClassCache($className = null) { 213 | 214 | $iterator = new \APCIterator('user'); 215 | while ($iterator->current()) { 216 | 217 | $tKey = $iterator->key(); 218 | 219 | if (mb_strpos ( $tKey, $className . '::' ) !== false) { 220 | apc_delete($tKey); 221 | } 222 | $iterator->next(); 223 | } 224 | 225 | } 226 | 227 | /** 228 | * 229 | * Flush opcode cache 230 | * @since 2012-08-01 231 | */ 232 | public function flushOpcode() { 233 | apc_clear_cache('opcode'); 234 | } 235 | 236 | /** 237 | * Oczyszczenie całego cache 238 | */ 239 | public function clearAll() { 240 | apc_clear_cache('user'); 241 | } 242 | 243 | /** 244 | * Zestawienie klucza 245 | * @param string $module 246 | * @param string $property 247 | * @return string 248 | */ 249 | private function getKey($module, $property) { 250 | return self::$sCachePrefix.'__'.$module.'||'.$property; 251 | } 252 | } -------------------------------------------------------------------------------- /website/classes/View/Frontpage.php: -------------------------------------------------------------------------------- 1 | model = new $this->modelName(); 21 | 22 | } 23 | 24 | public function mainpage() 25 | { 26 | $oTemplate = new Templater('mainpage.html'); 27 | 28 | $oCurrent = $this->model->getCurrent(); 29 | $oTemplate->add($oCurrent); 30 | 31 | $oData = $this->model->getAverage(1); 32 | $oTemplate->add('1dTempAvg', Formater::formatFloat($oData->Temperature, 2)); 33 | $oTemplate->add('1dHumidityAvg', Formater::formatFloat($oData->Humidity, 2)); 34 | 35 | $oData = $this->model->getMin(1); 36 | $oTemplate->add('1dTempMin', Formater::formatFloat($oData->Temperature, 2)); 37 | $oTemplate->add('1dHumidityMin', Formater::formatFloat($oData->Humidity, 2)); 38 | 39 | $oData = $this->model->getMax(1); 40 | $oTemplate->add('1dTempMax', Formater::formatFloat($oData->Temperature, 2)); 41 | $oTemplate->add('1dHumidityMax', Formater::formatFloat($oData->Humidity, 2)); 42 | 43 | $oData = $this->model->getAverage(7); 44 | $oTemplate->add('7dTempAvg', Formater::formatFloat($oData->Temperature, 2)); 45 | $oTemplate->add('7dHumidityAvg', Formater::formatFloat($oData->Humidity, 2)); 46 | 47 | $oData = $this->model->getMin(7); 48 | $oTemplate->add('7dTempMin', Formater::formatFloat($oData->Temperature, 2)); 49 | $oTemplate->add('7dHumidityMin', Formater::formatFloat($oData->Humidity, 2)); 50 | 51 | $oData = $this->model->getMax(7); 52 | $oTemplate->add('7dTempMax', Formater::formatFloat($oData->Temperature, 2)); 53 | $oTemplate->add('7dHumidityMax', Formater::formatFloat($oData->Humidity, 2)); 54 | 55 | return (string) $oTemplate; 56 | 57 | } 58 | 59 | public function tables() 60 | { 61 | $oTemplate = new Templater('tables.html'); 62 | 63 | /* 64 | * Get readout history 65 | */ 66 | $aHistory = $this->model->getHistory(); 67 | 68 | $sTable = ''; 69 | foreach ($aHistory as $iIndex => $oReadout) { 70 | 71 | $sTable .= ''; 72 | $sTable .= ''.($iIndex+1).''; 73 | $sTable .= ''.Formater::formatDateTime($oReadout['Date']).''; 74 | $sTable .= ''.$oReadout['Temperature'].'°C'; 75 | $sTable .= ''.$oReadout['Humidity'].'%'; 76 | $sTable .= ''; 77 | 78 | } 79 | $oTemplate->add('Table', $sTable); 80 | 81 | /* 82 | * Get daily aggregate 83 | */ 84 | $aHistory = $this->model->getDayAggregate(14); 85 | $sTable = ''; 86 | foreach ($aHistory as $iIndex => $oReadout) { 87 | 88 | $sTable .= ''; 89 | $sTable .= ''.Formater::formatDate($oReadout['Date']).''; 90 | $sTable .= ''.Formater::formatFloat($oReadout['MinTemperature'],2).'°C'; 91 | $sTable .= ''.Formater::formatFloat($oReadout['Temperature'],2).'°C'; 92 | $sTable .= ''.Formater::formatFloat($oReadout['MaxTemperature'],2).'°C'; 93 | $sTable .= ''.Formater::formatFloat($oReadout['MinHumidity'],2).'%'; 94 | $sTable .= ''.Formater::formatFloat($oReadout['Humidity'],2).'%'; 95 | $sTable .= ''.Formater::formatFloat($oReadout['MaxHumidity'],2).'%'; 96 | $sTable .= ''; 97 | 98 | } 99 | $oTemplate->add('DailyTable', $sTable); 100 | 101 | return (string) $oTemplate; 102 | } 103 | 104 | public function charts() 105 | { 106 | $oTemplate = new Templater('charts.html'); 107 | 108 | return (string) $oTemplate; 109 | } 110 | 111 | /** 112 | * render average temperature chart head for google charts 113 | * @return string 114 | */ 115 | public function chartHead() { 116 | 117 | $oTemplate = new Templater('chartHead.html'); 118 | 119 | /* 120 | * Hour Aggregate charts 121 | */ 122 | $aHistory = $this->model->getHourAggregate(72,"ASC"); 123 | 124 | $oChartHourTemperature = new \General\GoogleChart(); 125 | $oChartHourTemperature->setTitle('Temperature'); 126 | $oChartHourTemperature->setDomID('chartHourTemperature'); 127 | $oChartHourTemperature->add('Hour', array()); 128 | $oChartHourTemperature->add('Avg', array()); 129 | $oChartHourTemperature->add('Max', array()); 130 | $oChartHourTemperature->add('Min', array()); 131 | 132 | $oChartHourHumidity = new \General\GoogleChart(); 133 | $oChartHourHumidity->setTitle('Humidity'); 134 | $oChartHourHumidity->setDomID('chartHourHumidity'); 135 | $oChartHourHumidity->add('Hour', array()); 136 | $oChartHourHumidity->add('Avg', array()); 137 | $oChartHourHumidity->add('Max', array()); 138 | $oChartHourHumidity->add('Min', array()); 139 | 140 | foreach ($aHistory as $iIndex => $oReadout) { 141 | 142 | $oChartHourTemperature->push('Hour', Formater::formatTime($oReadout['Date'])); 143 | $oChartHourTemperature->push('Avg', number_format($oReadout['Temperature'],2)); 144 | $oChartHourTemperature->push('Max', number_format($oReadout['MaxTemperature'],2)); 145 | $oChartHourTemperature->push('Min', number_format($oReadout['MinTemperature'],2)); 146 | 147 | $oChartHourHumidity->push('Hour', Formater::formatTime($oReadout['Date'])); 148 | $oChartHourHumidity->push('Avg', number_format($oReadout['Humidity'],2)); 149 | $oChartHourHumidity->push('Max', number_format($oReadout['MaxHumidity'],2)); 150 | $oChartHourHumidity->push('Min', number_format($oReadout['MinHumidity'],2)); 151 | 152 | } 153 | $oTemplate->add('chartHourTemperature',$oChartHourTemperature->getHead()); 154 | $oTemplate->add('chartHourHumidity',$oChartHourHumidity->getHead()); 155 | 156 | /* 157 | * Day aggregate charts 158 | */ 159 | 160 | $aHistory = $this->model->getDayAggregate(14,"ASC"); 161 | 162 | $oChartDailyTemperature = new \General\GoogleChart(); 163 | $oChartDailyTemperature->setTitle('Temperature'); 164 | $oChartDailyTemperature->setDomID('chartDailyTemperature'); 165 | $oChartDailyTemperature->add('Day', array()); 166 | $oChartDailyTemperature->add('Avg', array()); 167 | $oChartDailyTemperature->add('Max', array()); 168 | $oChartDailyTemperature->add('Min', array()); 169 | 170 | $oChartDailyHumidity = new \General\GoogleChart(); 171 | $oChartDailyHumidity->setTitle('Humidity'); 172 | $oChartDailyHumidity->setDomID('chartDailyHumidity'); 173 | $oChartDailyHumidity->add('Day', array()); 174 | $oChartDailyHumidity->add('Avg', array()); 175 | $oChartDailyHumidity->add('Max', array()); 176 | $oChartDailyHumidity->add('Min', array()); 177 | 178 | foreach ($aHistory as $iIndex => $oReadout) { 179 | 180 | $oChartDailyTemperature->push('Day', Formater::formatDate($oReadout['Date'])); 181 | $oChartDailyTemperature->push('Avg', number_format($oReadout['Temperature'],2)); 182 | $oChartDailyTemperature->push('Max', number_format($oReadout['MaxTemperature'],2)); 183 | $oChartDailyTemperature->push('Min', number_format($oReadout['MinTemperature'],2)); 184 | 185 | $oChartDailyHumidity->push('Day', Formater::formatDate($oReadout['Date'])); 186 | $oChartDailyHumidity->push('Avg', number_format($oReadout['Humidity'],2)); 187 | $oChartDailyHumidity->push('Max', number_format($oReadout['MaxHumidity'],2)); 188 | $oChartDailyHumidity->push('Min', number_format($oReadout['MinHumidity'],2)); 189 | 190 | } 191 | $oTemplate->add('chartDailyTemperature',$oChartDailyTemperature->getHead()); 192 | $oTemplate->add('chartDailyHumidity',$oChartDailyHumidity->getHead()); 193 | 194 | return (string) $oTemplate; 195 | 196 | } 197 | 198 | } -------------------------------------------------------------------------------- /website/classes/Cache/File.php: -------------------------------------------------------------------------------- 1 | 9 | * @see http://www.spychalski.info 10 | * @category Common 11 | * @version 0.9 12 | */ 13 | class File{ 14 | 15 | /** 16 | * Tablica wpisów w cache 17 | * 18 | * @var array 19 | */ 20 | private $elements = array (); 21 | 22 | /** 23 | * Nazwa pliku przechowującego cache 24 | * 25 | * @var string 26 | */ 27 | private $fileName = null; 28 | 29 | /** 30 | * Domyślny czas ważności cache [s] 31 | * 32 | * @var int 33 | */ 34 | private $timeThreshold = 1200; 35 | 36 | /** 37 | * Maksymalny rozmiar cache 38 | * 39 | * @var int 40 | */ 41 | private $maxSize = 2000; 42 | 43 | /** 44 | * Obecny rozmiar 45 | * 46 | * @var int 47 | */ 48 | private $currentSize = 0; 49 | 50 | /** 51 | * Czy zawartość cache zmieniła się po załadowaniu/utworzeniu 52 | * 53 | * @var boolean 54 | */ 55 | private $changed = false; 56 | 57 | /** 58 | * Nazwa wpisu w $_SESSION przechowującego następny czas oczyszczania 59 | * 60 | * @var string 61 | */ 62 | private $cacheMaintenanceTimeName = 'CacheOverFileMaintnance'; 63 | 64 | /** 65 | * Czy dokonuwać kompresji pliku cache 66 | * 67 | * @var boolean 68 | */ 69 | private $useZip = true; 70 | 71 | /** 72 | * Obiekt klasy -> Singleton 73 | * @var CacheOverFile 74 | */ 75 | private static $instance; 76 | 77 | public static function getInstance(){ 78 | if (empty(self::$instance)) { 79 | $className = __CLASS__; 80 | self::$instance = new $className; 81 | } 82 | return self::$instance; 83 | } 84 | 85 | /** 86 | * Destruktor 87 | * 88 | */ 89 | public function __destruct() { 90 | 91 | $this->synchronize (); 92 | } 93 | 94 | /** 95 | * konstruktor 96 | * 97 | * @param int $userID 98 | */ 99 | private function __construct() { 100 | 101 | $this->fileName = dirname ( __FILE__ ) . "/../../../userData/" . get_class () . '.sca'; 102 | 103 | $this->load (); 104 | 105 | } 106 | 107 | /** 108 | * Pobranie cache 109 | */ 110 | private function load() { 111 | 112 | try { 113 | 114 | if (file_exists ( $this->fileName )) { 115 | $tCounter = 0; 116 | $tFile = fopen ( $this->fileName, 'r' ); 117 | 118 | /* 119 | * Załóż blokadę na plik cache 120 | */ 121 | while ( ! flock ( $tFile, LOCK_SH ) ) { 122 | usleep ( 5 ); 123 | $tCounter ++; 124 | if ($tCounter == 100) { 125 | return false; 126 | } 127 | } 128 | 129 | $tContent = fread ( $tFile, filesize ( $this->fileName ) ); 130 | 131 | if ($this->useZip) { 132 | $tContent = gzuncompress ( $tContent ); 133 | } 134 | 135 | $this->elements = unserialize ( $tContent ); 136 | 137 | flock ( $tFile, LOCK_UN ); 138 | fclose ( $tFile ); 139 | 140 | $tKeys = array_keys ( $this->elements ); 141 | foreach ( $tKeys as $tKey ) { 142 | $this->maintenace ( $tKey ); 143 | } 144 | 145 | } 146 | } catch ( Exception $e ) { 147 | psDebug::cThrow ( null, $e, array ('display' => false, 'send' => true ) ); 148 | } 149 | return true; 150 | } 151 | 152 | /** 153 | * Synchronizacja cache z plikiem 154 | * 155 | * @return boolean 156 | */ 157 | function synchronize() { 158 | 159 | try { 160 | $tCounter = 0; 161 | 162 | if ($this->changed) { 163 | $tFile = fopen ( $this->fileName, 'a' ); 164 | 165 | /* 166 | * Załóż blokadę na plik cache 167 | */ 168 | while ( ! flock ( $tFile, LOCK_EX ) ) { 169 | usleep ( 5 ); 170 | $tCounter ++; 171 | if ($tCounter == 100) { 172 | return false; 173 | } 174 | } 175 | 176 | /* 177 | * Jeśli udało się założyć blokadę, zapisz elementy 178 | */ 179 | $tContent = serialize ( $this->elements ); 180 | 181 | ftruncate ( $tFile, 0 ); 182 | 183 | if ($this->useZip) { 184 | $tContent = gzcompress ( $tContent ); 185 | } 186 | 187 | fputs ( $tFile, $tContent ); 188 | 189 | flock ( $tFile, LOCK_UN ); 190 | fclose ( $tFile ); 191 | return true; 192 | } 193 | } catch ( Exception $e ) { 194 | psDebug::cThrow ( null, $e, array ('display' => false, 'send' => true ) ); 195 | return false; 196 | } 197 | return true; 198 | } 199 | 200 | /** 201 | * Oczyszczanie wybranego modułu 202 | * 203 | * @param string $module 204 | * @return boolean 205 | */ 206 | private function maintenace($module) { 207 | 208 | if (! isset ( $this->elements [$module] )) 209 | return false; 210 | 211 | if (! isset ( $_SESSION [$this->cacheMaintenanceTimeName] [$module] )) { 212 | $_SESSION [$this->cacheMaintenanceTimeName] [$module] = time (); 213 | } 214 | 215 | //Sprawdz, czy wykonać czyszczenie 216 | if (time () < $_SESSION [$this->cacheMaintenanceTimeName] [$module]) 217 | return false; 218 | 219 | //Ustaw czas następnego czyszczenia 220 | $_SESSION [$this->cacheMaintenanceTimeName] [$module] = time () + $this->timeThreshold; 221 | 222 | //Pobierz wszystkie klucze w module 223 | $keys = array_keys ( $this->elements [$module] ); 224 | 225 | //Wykonaj pętlę po kluczach 226 | foreach ( $keys as $value ) { 227 | //Oczyść przeterminowane klucze 228 | if (time () > $this->elements [$module] [$value]->getTime ()) { 229 | unset ( $this->elements [$module] [$value] ); 230 | $this->changed = true; 231 | } 232 | } 233 | 234 | return true; 235 | 236 | } 237 | 238 | /** 239 | * Sprawdzenie, czy w cache znajduje się wpis 240 | * 241 | * @param string $module 242 | * @param string $property 243 | * @return boolean 244 | */ 245 | function check($module, $property) { 246 | 247 | if (isset ( $this->elements [$module] [$property] )) { 248 | return true; 249 | } else { 250 | return false; 251 | } 252 | } 253 | 254 | /** 255 | * Pobranie wartości z cache 256 | * 257 | * @param string $module 258 | * @param string $property 259 | * @return mixed 260 | */ 261 | function get($module, $property) { 262 | 263 | if (isset ( $this->elements [$module] [$property] )) { 264 | $tValue = $this->elements [$module] [$property]->getValue (); 265 | return $tValue; 266 | } else { 267 | return NULL; 268 | } 269 | } 270 | 271 | /** 272 | * Wyczyszczenie konkretnego wpisu w cache 273 | * 274 | * @param string $module 275 | * @param string $property 276 | */ 277 | function clear($module, $property) { 278 | 279 | if (isset ( $this->elements [$module] [$property] )) { 280 | unset ( $this->elements [$module] [$property] ); 281 | $this->changed = true; 282 | } 283 | 284 | } 285 | 286 | /** 287 | * Wyczyszczenie konkretnego modułu cache 288 | * 289 | * @param string $module 290 | */ 291 | function clearModule($module) { 292 | 293 | if (isset ( $this->elements [$module] )) { 294 | unset ( $this->elements [$module] ); 295 | $this->changed = true; 296 | } 297 | 298 | } 299 | 300 | /** 301 | * Wstawienei do cache 302 | * 303 | * @param string $module 304 | * @param string $property 305 | * @param mixed $value 306 | * @param int $sessionLength 307 | */ 308 | function set($module, $property, $value, $sessionLength = null) { 309 | 310 | if ($sessionLength == null) { 311 | $sessionLength = $this->timeThreshold; 312 | } 313 | 314 | if (! isset ( $this->elements [$module] [$property] )) { 315 | $this->elements [$module] [$property] = new FileElement ( $value, time () + $sessionLength ); 316 | } else { 317 | $this->elements [$module] [$property]->set ( $value, time () + $sessionLength); 318 | } 319 | 320 | /* 321 | * Określ czas następnego czyszczenia cache dla tego modułu 322 | */ 323 | if (! isset ( $_SESSION [$this->cacheMaintenanceTimeName] [$module] )) { 324 | $_SESSION [$this->cacheMaintenanceTimeName] [$module] = time () + $sessionLength; 325 | } 326 | 327 | $this->changed = true; 328 | } 329 | 330 | /** 331 | * Wyczyszczenie wpisów zależnych od podanej klasy 332 | * 333 | * @param string $className 334 | */ 335 | public function clearClassCache($className) { 336 | 337 | $tKeys = array_keys ( $this->elements ); 338 | foreach ( $tKeys as $tKey ) { 339 | if (mb_strpos ( $tKey, $className . '::' ) !== false) { 340 | $this->clearModule ( $tKey ); 341 | } 342 | } 343 | } 344 | 345 | /** 346 | * Oczyszczenie wszystkich wpisów w cache 347 | * 348 | */ 349 | private function globalMaintnance() { 350 | 351 | $tKeys = array_keys ( $this->elements ); 352 | foreach ( $tKeys as $tKey ) { 353 | $this->maintenace ( $tKey ); 354 | } 355 | 356 | } 357 | 358 | /** 359 | * Pobranie łącznej liczby modułów 360 | */ 361 | public function getCount() { 362 | return count($this->elements); 363 | } 364 | 365 | /** 366 | * Pobranie łączniej liczby wpisów 367 | */ 368 | public function getTotalCount() { 369 | 370 | $retVal = $this->getCount(); 371 | 372 | foreach ($this->elements as $tElement) { 373 | $retVal += count($tElement); 374 | } 375 | 376 | return $retVal; 377 | } 378 | 379 | /** 380 | * Oczyszczenie całego cache 381 | */ 382 | public function clearAll() { 383 | $this->elements = array(); 384 | } 385 | 386 | public function debug() { 387 | \psDebug::print_r($this->elements); 388 | } 389 | 390 | } -------------------------------------------------------------------------------- /website/classes/General/Debug.php: -------------------------------------------------------------------------------- 1 | 9 | * @link http://www.spychalski.info 10 | * @version 0.6.5 11 | * @category Common 12 | * @copyright 2009 Lynx-IT Pawel Stanislaw Spychalski 13 | * @license MIT 14 | * @see wfErrorHandler by Grzegorz Godlewski 15 | * 16 | */ 17 | class Debug { 18 | 19 | /** 20 | * Display error code and trace? 21 | * 22 | * @var boolean 23 | */ 24 | static $displayTrace = true; 25 | 26 | /** 27 | * Send error code using psErrorSender? 28 | * 29 | * @var boolean 30 | */ 31 | static $sendTrace = false; 32 | 33 | /** 34 | * Write error code? 35 | * 36 | * @var boolean 37 | */ 38 | static $writeTrace = false; 39 | 40 | static $writeFile = 'error.log'; 41 | 42 | /** 43 | * display error on uncaght exceptions and errors? 44 | * 45 | * @var boolean 46 | */ 47 | static $displayErrors = true; 48 | 49 | /** 50 | * Standard error message 51 | * 52 | * @var string 53 | */ 54 | static $standardErrorText = 'Unexpected error!'; 55 | 56 | /** 57 | * Additional error text 58 | * 59 | * @var string 60 | */ 61 | static $additionalErrorText = ''; 62 | 63 | /** 64 | * error sender configuration array 65 | * 66 | * @var array 67 | */ 68 | static $senderConfig = array ('url' => '', 'path' => '', 'port' => 80, 'sender' => 'unknown' ); 69 | 70 | /** 71 | * Enter description here... 72 | * 73 | * @var boolean 74 | */ 75 | static $errorHoldsExecution = true; 76 | 77 | /** 78 | * Error names 79 | * 80 | * @var array 81 | */ 82 | protected static $errorType = array (E_ERROR => 'ERROR', E_WARNING => 'WARNING', E_PARSE => 'PARSING ERROR', E_NOTICE => 'NOTICE', E_CORE_ERROR => 'CORE ERROR', E_CORE_WARNING => 'CORE WARNING', E_COMPILE_ERROR => 'COMPILE ERROR', E_COMPILE_WARNING => 'COMPILE WARNING', E_USER_ERROR => 'USER ERROR', E_USER_WARNING => 'USER WARNING', E_USER_NOTICE => 'USER NOTICE', E_STRICT => 'STRICT NOTICE', E_RECOVERABLE_ERROR => 'RECOVERABLE ERROR' ); 83 | 84 | /** 85 | * Get prased microtime 86 | * 87 | * @return float 88 | */ 89 | static function sGetMicrotime() { 90 | list ( $usec, $sec ) = explode ( " ", microtime () ); 91 | return (( float ) $usec + ( float ) $sec); 92 | } 93 | 94 | /** 95 | * static constructor 96 | * 97 | */ 98 | static public function create() { 99 | 100 | if (self::$displayErrors) { 101 | $flags = E_ALL; 102 | ini_set ( 'display_errors', 1 ); 103 | } else { 104 | $flags = 0; 105 | ini_set ( 'display_errors', 0 ); 106 | } 107 | 108 | set_error_handler ( array ('\General\Debug', "errorHandler" ), $flags ); 109 | set_exception_handler ( array ('\General\Debug', "exceptionHandler" ) ); 110 | 111 | } 112 | 113 | /** 114 | * function formats error to readable form 115 | * 116 | * @param string $errno 117 | * @param string $errstr 118 | * @param string $errfile 119 | * @param string $errline 120 | * @return string 121 | */ 122 | static protected function formatErrorText($errno, $errstr, $errfile, $errline) { 123 | 124 | $retVal = '
' . self::$errorType [$errno] . ': ' . $errstr . '
'; 125 | $retVal .= '
File: ' . $errfile . '
'; 126 | $retVal .= '
Line: ' . $errline . '
'; 127 | 128 | return $retVal; 129 | 130 | } 131 | 132 | /** 133 | * Formats error message and returns as string 134 | * 135 | * @param string $text 136 | * @return string 137 | */ 138 | static protected function formatError($text) { 139 | 140 | $retVal = '
' . $text . '
'; 141 | 142 | return $retVal; 143 | } 144 | 145 | /** 146 | * Returns 'nice' formatted error message 147 | * 148 | * @param string $text 149 | * @param array $config 150 | * @return string 151 | */ 152 | static public function displayBox($text = '', $config = null) { 153 | 154 | if (! isset ( $config ['attach'] )) { 155 | $config ['attach'] = true; 156 | } 157 | 158 | if ($text == '') { 159 | $text = self::$standardErrorText; 160 | } 161 | 162 | $retVal = '

' . $text . '

'; 163 | 164 | if ($config ['attach'] && ! empty ( self::$additionalErrorText )) { 165 | $retVal .= '

' . self::$additionalErrorText . '

'; 166 | } 167 | 168 | $retVal = "
" . $retVal . "
"; 169 | 170 | return $retVal; 171 | 172 | } 173 | 174 | /** 175 | * Error handler 176 | * 177 | * @param string $errno 178 | * @param string $errstr 179 | * @param string $errfile 180 | * @param string $errline 181 | */ 182 | static public function errorHandler($errno, $errstr, $errfile, $errline) { 183 | 184 | /* 185 | * Is line has been supressed with an @, do not throw an exception 186 | */ 187 | if (error_reporting () == 0) { 188 | return; 189 | } 190 | 191 | $errorFullText = self::formatErrorText ( $errno, $errstr, $errfile, $errline ); 192 | 193 | /* 194 | * Hold execution 195 | */ 196 | if (self::$errorHoldsExecution) { 197 | throw new DebugException ( $errorFullText, $errno ); 198 | } else { 199 | /* 200 | * display error 201 | */ 202 | if (self::$displayErrors) { 203 | echo self::displayBox (); 204 | } 205 | /* 206 | * Message error 207 | */ 208 | if (self::$displayTrace) { 209 | echo self::formatError ( $errorFullText ); 210 | } 211 | 212 | /* 213 | * Send message do psHelpdesk 214 | */ 215 | if (self::$sendTrace) { 216 | self::send ( $errorFullText ); 217 | } 218 | } 219 | 220 | } 221 | 222 | /** 223 | * Formats exception messages 224 | * 225 | * @param Exception $exception 226 | * @return string 227 | */ 228 | static protected function formatExceptionMessage(\Exception $exception) { 229 | 230 | $errorFullText = '
New ' . get_class ( $exception ) . '
'; 231 | $errorFullText .= '
File: ' . $exception->getFile () . '
'; 232 | $errorFullText .= '
Line: ' . $exception->getLine () . '
'; 233 | $errorFullText .= '
Message: ' . $exception->getMessage () . '
'; 234 | 235 | $trace = $exception->getTrace (); 236 | 237 | if (get_class ( $exception ) != 'DebugException') { 238 | array_unshift ( $trace, array ('file' => $exception->getFile (), 'line' => $exception->getLine (), 'function' => 'throw ' . get_class ( $exception ), 'args' => array ($exception->getMessage (), $exception->getCode () ) ) ); 239 | } 240 | 241 | $traceString = ''; 242 | foreach ( $trace as $tTraceItem ) { 243 | 244 | if (empty ( $tTraceItem ['file'] )) { 245 | $tTraceItem ['file'] = ''; 246 | } 247 | if (empty ( $tTraceItem ['line'] )) { 248 | $tTraceItem ['line'] = ''; 249 | } 250 | 251 | $traceString .= '
  • ' . basename ( $tTraceItem ['file'] ) . " at line #" . $tTraceItem ['line'] . "\t"; 252 | if (isset ( $tTraceItem ['class'] )) { 253 | $traceString .= $tTraceItem ['class'] . '::' . $tTraceItem ['function'] . '('; 254 | } elseif (isset ( $tTraceItem ['function'] )) { 255 | $traceString .= $tTraceItem ['function'] . '('; 256 | } 257 | 258 | if (! empty ( $tTraceItem ['args'] )) { 259 | $separator = ''; 260 | foreach ( $tTraceItem ['args'] as $arg ) { 261 | $traceString .= $separator . self::getArgument ( $arg ); 262 | $separator = ', '; 263 | } 264 | $traceString .= ')'; 265 | } 266 | $traceString .= "
  • "; 267 | } 268 | 269 | $errorFullText .= '
    Backtrace:
      ' . $traceString . '
    '; 270 | 271 | return $errorFullText; 272 | } 273 | 274 | /** 275 | * Exception handler 276 | * 277 | * @param exception $ex 278 | */ 279 | static public function exceptionHandler(\Exception $exception) { 280 | 281 | $errorFullText = self::formatExceptionMessage ( $exception ); 282 | 283 | if (self::$displayErrors) { 284 | echo self::displayBox (); 285 | } 286 | 287 | if (self::$displayTrace) { 288 | echo self::formatError ( $errorFullText ); 289 | } 290 | 291 | if (self::$sendTrace) { 292 | self::send ( $errorFullText ); 293 | } 294 | 295 | } 296 | 297 | /** 298 | * Converts variable into short text 299 | * 300 | * @param mixed $arg Variable 301 | * @return string 302 | */ 303 | static protected function getArgument($arg) { 304 | 305 | switch (mb_strtolower ( gettype ( $arg ) )) { 306 | case 'string' : 307 | return ('"' . str_replace ( array ("\n", "\"" ), array ('', '\"' ), $arg ) . '"'); 308 | 309 | case 'boolean' : 310 | return ( bool ) $arg; 311 | 312 | case 'object' : 313 | return 'object(' . get_class ( $arg ) . ')'; 314 | 315 | case 'array' : 316 | return 'array[' . count ( $arg ) . ']'; 317 | 318 | case 'resource' : 319 | return 'resource(' . get_resource_type ( $arg ) . ')'; 320 | 321 | default : 322 | return var_export ( $arg, true ); 323 | } 324 | } 325 | 326 | /** 327 | * Error sending function, sends messages psHelpdesk 328 | * 329 | * @param string $text 330 | * @return boolean 331 | */ 332 | static public function send($text) { 333 | 334 | /** 335 | * If sender configuration is missing, skip sending 336 | */ 337 | if (! self::$sendTrace || empty ( self::$senderConfig ['url'] ) || empty ( self::$senderConfig ['port'] )) { 338 | return false; 339 | } 340 | 341 | $data ['company'] = self::$senderConfig ['sender']; 342 | $data ['text'] = urlencode ( $text ); 343 | $data ['parameters'] = serialize ( $_REQUEST ); 344 | $data ['referer'] = $_SERVER ['HTTP_HOST']; 345 | $data ['userName'] = ''; 346 | 347 | $data = serialize ( $data ); 348 | 349 | $fp = fsockopen ( self::$senderConfig ['url'], self::$senderConfig ['port'], $errno, $errstr, 10 ); 350 | 351 | if (! $fp) { 352 | return false; 353 | } 354 | 355 | fputs ( $fp, "POST " . self::$senderConfig ['path'] . " HTTP/1.1\r\n" ); 356 | fputs ( $fp, "Host: " . self::$senderConfig ['url'] . "\r\n" ); 357 | fputs ( $fp, "Referer: " . $_SERVER ['HTTP_HOST'] . "\r\n" ); 358 | fputs ( $fp, "Content-type: application/x-www-form-urlencoded; charset=uft-8\r\n" ); 359 | fputs ( $fp, "Content-length: " . strlen ( $data ) . "\r\n" ); 360 | fputs ( $fp, "Connection: close\r\n\r\n" ); 361 | fputs ( $fp, $data ); 362 | 363 | fclose ( $fp ); 364 | 365 | return true; 366 | } 367 | 368 | /** 369 | * Error write function 370 | * 371 | * @param string $text 372 | * @return boolean 373 | */ 374 | static public function write($text) { 375 | 376 | $text = str_replace ( '
    ', '', $text ); 377 | $text = str_replace ( '
    ', '; ', $text ); 378 | 379 | $data ['text'] = "\n" . date ( 'Y-m-d H:i' ) . '; ' . $text; 380 | 381 | $data ['parameters'] = serialize ( $_REQUEST ); 382 | 383 | $tFile = fopen ( self::$writeFile, 'a' ); 384 | 385 | fputs ( $tFile, $data ['text'] ); 386 | 387 | fclose ( $tFile ); 388 | 389 | return true; 390 | } 391 | 392 | /** 393 | * Controlled throw for catch block 394 | * 395 | * @param string $message 396 | * @param Exception $exception 397 | * @param array $config 398 | * @return string 399 | */ 400 | static public function cThrow($message = null, \Exception $exception = null, $config = null) { 401 | 402 | if (! isset ( $config ['display'] )) { 403 | $config ['display'] = self::$displayTrace; 404 | } 405 | 406 | if (! isset ( $config ['send'] )) { 407 | $config ['send'] = self::$sendTrace; 408 | } 409 | 410 | if (! isset ( $config ['write'] )) { 411 | $config ['write'] = self::$writeTrace; 412 | } 413 | 414 | $retVal = ''; 415 | 416 | if (empty ( $message )) { 417 | $message = self::$standardErrorText; 418 | } 419 | 420 | $retVal .= self::displayBox ( $message ); 421 | 422 | /** 423 | * if exception has been sent, try to display or send it 424 | */ 425 | if (! empty ( $exception )) { 426 | 427 | $errorFullText = self::formatExceptionMessage ( $exception ); 428 | 429 | if ($config ['display']) { 430 | $retVal .= self::formatError ( $errorFullText ); 431 | } 432 | 433 | if ($config ['send']) { 434 | self::send ( $errorFullText ); 435 | } 436 | 437 | if ($config ['write']) { 438 | self::write ( $errorFullText ); 439 | } 440 | 441 | } 442 | 443 | return $retVal; 444 | } 445 | 446 | /** 447 | * Halt program execution 448 | * 449 | * @param string $message 450 | * @param Exception $exception 451 | * @param array $config 452 | */ 453 | static public function halt($message = null, \Exception $exception = null, $config = null) { 454 | 455 | echo self::cThrow ( $message, $exception, $config ); 456 | exit ( 0 ); 457 | } 458 | 459 | /** 460 | * print_r alias with
     and border
    461 | 	 *
    462 | 	 * @param mixed $value
    463 | 	 */
    464 | 	public static function print_r($value) {
    465 | 		
    466 | 		echo "
    ";
    467 | 		print_r ( $value );
    468 | 		echo "
    "; 469 | } 470 | 471 | } 472 | 473 | /** 474 | * psDebug exception class 475 | * 476 | * @author Pawel Spychalski 477 | * @link http://www.spychalski.info 478 | * @version 1 479 | * @category universal 480 | * @copyright 2009 Lynx-IT Pawel Stanislaw Spychalski 481 | * @see psDebug 482 | * 483 | */ 484 | class DebugException extends \Exception { 485 | 486 | } 487 | 488 | /** 489 | * Exception for custom usage 490 | * 491 | * @author Pawel Spychalski 492 | * @link http://www.spychalski.info 493 | * @version 1 494 | * @copyright 2009 Lynx-IT Pawel Stanislaw Spychalski 495 | * @see Debug 496 | */ 497 | class CustomException extends \Exception { 498 | 499 | } -------------------------------------------------------------------------------- /website/assets/bootstrap/css/bootstrap-responsive.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.3.1 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:inherit!important}.hidden-print{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} 10 | -------------------------------------------------------------------------------- /website/classes/Model/Base.php: -------------------------------------------------------------------------------- 1 | aParams['id']; 51 | } 52 | 53 | if (empty($iId)) { 54 | return false; 55 | } 56 | 57 | /** 58 | * @var \Cache\Memcached 59 | */ 60 | $oCache = \Cache\Factory::getInstance(); 61 | 62 | $oCache->clear(get_class($this) . '::loadDataObject', $iId); 63 | } 64 | 65 | /** 66 | * stdClass będący reprezentacją obiektu bazy danych 67 | * @var stdClass 68 | */ 69 | protected $dataObject = null; 70 | 71 | /** 72 | * Tablica parametrów przekazanych do modelu 73 | * @var array 74 | */ 75 | protected $aParams = array(); 76 | 77 | /** 78 | * Pobranie dataObject 79 | * @return stdClass 80 | */ 81 | public function getDataObject() 82 | { 83 | return $this->dataObject; 84 | } 85 | 86 | protected function loadDataObjectEncapsulate($val) { 87 | 88 | return "'".$val."'"; 89 | 90 | } 91 | 92 | /** 93 | * Metoda pobiera dane obiektu do właściwości dataObject 94 | * @throws \Exception 95 | */ 96 | protected function loadDataObject() 97 | { 98 | 99 | $oCache = \Cache\Factory::getInstance(); 100 | 101 | if (empty($this->aParams['id'])) { 102 | throw new \Exception('{T:Nie podano identyfikatora obiektu}'); 103 | } 104 | 105 | $sModule = get_class($this) . '::loadDataObject'; 106 | $sProperty = $this->aParams['id']; 107 | 108 | if (!$this->bUseCache || !$oCache->check($sModule, $sProperty)) { 109 | 110 | $sQuery = "SELECT 111 | {$this->selectList} 112 | FROM 113 | $this->tableList 114 | WHERE 115 | {$this->registryIdField}={$this->loadDataObjectEncapsulate($this->aParams['id'])} 116 | LIMIT 1"; 117 | 118 | $rQuery = Database::getInstance()->execute($sQuery); 119 | $this->dataObject = Database::getInstance()->fetch($rQuery); 120 | 121 | $oCache->set($sModule, $sProperty, $this->dataObject); 122 | } 123 | else { 124 | $this->dataObject = $oCache->get($sModule, $sProperty); 125 | } 126 | } 127 | 128 | /** 129 | * Ustawienie dodatkowych warunków dla modelu, wykorzystywane dla rejestrów 130 | */ 131 | protected function setConstrains() 132 | { 133 | 134 | } 135 | 136 | /** 137 | * Konstruktor 138 | * @param array $aParams 139 | */ 140 | public function __construct(array $aParams = null) 141 | { 142 | $this->aParams = $aParams; 143 | 144 | $this->tableList = $this->tableName . ' ' . $this->tableJoin; 145 | 146 | $this->setConstrains(); 147 | 148 | if (!empty($this->aParams['id'])) { 149 | $this->loadDataObject(); 150 | } 151 | } 152 | 153 | /** 154 | * 155 | * Pobranie nazwy pola identyfikującego wiersz 156 | * @return string 157 | */ 158 | public function getRegistryIdField() 159 | { 160 | return $this->registryIdField; 161 | } 162 | 163 | /** 164 | * Prztygotowanie warunku zapytania dla rejstru 165 | * @param string $sSearchIn 166 | * @param string $sSearchValue 167 | * @param string $sStartDate 168 | * @param string $sEndDate 169 | * @param boolean $bUseDateSelect 170 | * @return string 171 | */ 172 | public function prepareWhere($sSearchIn, $sSearchValue, $sStartDate, $sEndDate, $bUseDateSelect = false) 173 | { 174 | 175 | /* 176 | * Warunek wyszukiwania w rejestrze 177 | */ 178 | $set = false; 179 | 180 | if (!empty($this->aParams['constraints'])) { 181 | 182 | $set = true; 183 | 184 | $sCondition = ''; 185 | 186 | foreach ($this->aParams['constraints'] as $sKey => $sValue) { 187 | 188 | $sCondition .= " AND {$sKey}='{$sValue}' "; 189 | } 190 | 191 | if (mb_strlen($sCondition) > 0) { 192 | $sCondition = mb_substr($sCondition, 4); 193 | } 194 | 195 | $this->registryWhere .= $sCondition; 196 | } 197 | 198 | 199 | if ($sSearchValue != '') { 200 | 201 | if ($set) { 202 | $this->registryWhere .= " AND "; 203 | } 204 | 205 | $this->registryWhere .= $sSearchIn . " LIKE '%" . $sSearchValue . "%'"; 206 | $set = true; 207 | } 208 | 209 | /* 210 | * Selektor dat 211 | */ 212 | if ($bUseDateSelect) { 213 | 214 | if ($set) { 215 | $this->registryWhere .= " AND "; 216 | } 217 | $this->registryWhere .= $this->tableDateField . " >= '" . $sStartDate . "' AND " . $this->tableDateField . " <= '" . $sEndDate . "'"; 218 | $set = true; 219 | } 220 | 221 | } 222 | 223 | /** 224 | * Pobranie pojedynczej strony rejestru 225 | * @param int $iLimitSkip 226 | * @param int $iLimitNumber 227 | * @return resource 228 | */ 229 | public function getRegistryResults($iLimitSkip, $iLimitNumber) 230 | { 231 | 232 | $tQuery = "SELECT {$this->selectList} FROM {$this->tableList} WHERE {$this->fixEmptyWhere()} ORDER BY {$this->registryOrder} LIMIT {$iLimitSkip},{$iLimitNumber} "; 233 | 234 | return Database::getInstance()->execute($tQuery); 235 | } 236 | 237 | /** 238 | * Przygotowanie warunku sortowania do zapytania o wyniki rejestru 239 | * @param string $sSortBy 240 | * @param string $sSortDirection 241 | */ 242 | public function prepareSorting($sSortBy, $sSortDirection) 243 | { 244 | 245 | $this->registryOrder = $sSortBy . " " . $sSortDirection; 246 | } 247 | 248 | /** 249 | * 250 | * Pobranie liczby wyników w rejstrze spełniających warunki 251 | * @return int 252 | */ 253 | public function getRegistryCount() 254 | { 255 | 256 | $tQuery = Database::getInstance()->execute("SELECT COUNT($this->selectCountField) AS ile FROM {$this->tableList} WHERE {$this->fixEmptyWhere()}"); 257 | while ($tResult = Database::getInstance()->fetch($tQuery)) { 258 | return $tResult->ile; 259 | } 260 | } 261 | 262 | /** 263 | * Naprawienie przypadku gdy warunek WHERE jest pusty 264 | * 265 | * @return string 266 | */ 267 | protected function fixEmptyWhere() 268 | { 269 | 270 | $sRetVal = ""; 271 | 272 | if ($this->extraList == "" && $this->registryWhere == "") { 273 | $sRetVal = "1"; 274 | } 275 | elseif ($this->extraList != "" && $this->registryWhere == "") { 276 | $sRetVal = $this->extraList; 277 | } 278 | elseif ($this->extraList == "" && $this->registryWhere != "") { 279 | $sRetVal = $this->registryWhere; 280 | } 281 | elseif ($this->extraList != "" && $this->registryWhere != "") { 282 | $sRetVal = $this->extraList . " AND " . $this->registryWhere; 283 | } 284 | 285 | return $sRetVal; 286 | } 287 | 288 | protected function prepareGetAllQuery() 289 | { 290 | 291 | $sRetVal = 'SELECT ' . $this->selectList . ' FROM ' . $this->tableList; 292 | 293 | if (!empty($this->getAllSorting)) { 294 | $sRetVal .= ' ORDER BY ' . $this->getAllSorting; 295 | } 296 | 297 | return $sRetVal; 298 | } 299 | 300 | /** 301 | * Funkcja zwracająca tablię wszystkich elementów 302 | * 303 | * @return array Tablica elementów 304 | * @throws 305 | * @since 2012-06-18 306 | * @version 1.0 307 | */ 308 | public function getAll() 309 | { 310 | $res = Database::getInstance()->execute($this->prepareGetAllQuery()); 311 | $aUsergroup = array(); 312 | 313 | while ($oData = Database::getInstance()->fetch($res)) { 314 | $aUsergroup[] = get_object_vars($oData); 315 | } 316 | 317 | return $aUsergroup; 318 | } 319 | 320 | /** 321 | * Funkcja przygotowująca zapytanie z WHERE 322 | * 323 | * @param array $aTerms tablica warunków klucz=>wartosc 324 | * @param array $aTermsOR tablica warunków "OR" array(kolumna=>array(wartosc1,wartosc2)) 325 | * @return string zapytanie 326 | * @throws 327 | * @since 2012-10-01 328 | * @version 2.0 329 | */ 330 | 331 | protected function prepareGetAllWhereQuery($aTerms,$aTermsOR) 332 | { 333 | 334 | $sRetVal = 'SELECT ' . $this->selectList . ' FROM ' . $this->tableList.' WHERE ' ; 335 | 336 | if($aTerms!=null){ 337 | foreach ($aTerms as $key => $val){ 338 | $sWhere[]= $key ."=". $val; 339 | } 340 | } 341 | 342 | if($aTermsOR!=null){ 343 | foreach ($aTermsOR as $column => $values){ 344 | 345 | foreach($values as $key=>$val){ 346 | 347 | $sOr[]=$column."=".$val; 348 | } 349 | 350 | $sWhere[]="(".implode($sOr," OR ").")"; 351 | } 352 | 353 | } 354 | 355 | 356 | $sRetVal.=implode($sWhere," AND "); 357 | 358 | if (!empty($this->getAllSorting)) { 359 | $sRetVal .= ' ORDER BY ' . $this->getAllSorting; 360 | 361 | if (!empty($this->getAllSortingDir)) { 362 | $sRetVal .= ' ' . $this->getAllSortingDir; 363 | } 364 | 365 | } 366 | 367 | return $sRetVal; 368 | } 369 | 370 | /** 371 | * Funkcja zwracająca tablię wszystkich elementów z uwzględnieniem warunków WHERE 372 | * 373 | * @param array $aTerms tablica warunków klucz=>wartosc 374 | * @return array Tablica elementów 375 | * @throws 376 | * @since 2012-10-01 377 | * @version 1.0 378 | */ 379 | 380 | public function getAllWhere($aTerms=null,$aTermsOR=null) 381 | { 382 | $res = Database::getInstance()->execute($this->prepareGetAllWhereQuery($aTerms,$aTermsOR)); 383 | $aUsergroup = array(); 384 | 385 | while ($oData = Database::getInstance()->fetch($res)) { 386 | $aUsergroup[] = get_object_vars($oData); 387 | } 388 | 389 | return $aUsergroup; 390 | } 391 | 392 | /** 393 | * Funkcja zwracająca tablię wybranych elementów Klucz - Wartość 394 | * 395 | * @param string $key Klucz 396 | * @param string $value Wartość 397 | * @return array Tablica elementów 398 | * @throws 399 | * @since 2012-06-18 400 | * @version 1.0 401 | */ 402 | public function getAllKeyValue($key, $value, $addEmpty = false) 403 | { 404 | $res = Database::getInstance()->execute($this->prepareGetAllQuery()); 405 | $aUsergroup = array(); 406 | 407 | if ($addEmpty) { 408 | $aUsergroup[''] = '-'; 409 | } 410 | 411 | while ($oData = Database::getInstance()->fetch($res)) { 412 | $aUsergroup[$oData->{$key}] = $oData->{$value}; 413 | } 414 | 415 | return $aUsergroup; 416 | } 417 | 418 | /** 419 | * Funkcja usuwająca element o podanym id 420 | * 421 | * @param int $id id elementu do usunięcia 422 | * @return 423 | * @throws 424 | * @since 2012-06-15 425 | * @version 1.0 426 | */ 427 | public function deleteById($id) 428 | { 429 | $a = Database::getInstance()->execute('DELETE FROM ' . $this->tableName . ' WHERE ' . $this->registryIdField . ' = ' . $id); 430 | 431 | /* 432 | * Zrzuć cache 433 | */ 434 | $this->dropCache($id); 435 | } 436 | 437 | /** 438 | * Funkcja usuwająca element o podanych warunkach 439 | * 440 | * @param array $params tablica parametrów 441 | * @return 442 | * @throws 443 | * @since 2012-09-5 444 | * @version 1.0 445 | */ 446 | public function delete($params) 447 | { 448 | 449 | $aWhere = array(); 450 | foreach ($params as $key => $value) { 451 | $aWhere[] = '`' . $key . '`' . ' = ' . $value; 452 | } 453 | $sWhere = implode(' AND ', $aWhere); 454 | $a = Database::getInstance()->execute('DELETE FROM ' . $this->tableName . ' WHERE ' . $sWhere); 455 | 456 | /* 457 | * Zrzuć cache 458 | */ 459 | $this->dropCache($this->aParams['id']); 460 | } 461 | 462 | public function checkIfExists($sKey, $mValue = null, $iId = null, $getId = false) 463 | { 464 | $sSql = 'SELECT ' . $this->registryIdField . ' FROM ' . $this->tableName . ' WHERE '; 465 | 466 | if (!is_array($sKey)) { 467 | $aParams = array($sKey => $mValue); 468 | } 469 | else { 470 | $aParams = $sKey; 471 | } 472 | $aWhere = array(); 473 | foreach ($aParams as $sKey => $sValue) { 474 | switch (gettype($sValue)) { 475 | case 'integer': 476 | $aWhere[] = '`' . $sKey . '` = ' . $sValue; 477 | break; 478 | case 'string': 479 | $aWhere[] = '`' . $sKey . '` = "' . $sValue . '"'; 480 | break; 481 | default: 482 | throw new \Exception('Bad value type. Only string and integer accepted'); 483 | break; 484 | } 485 | } 486 | $sQuery = $sSql . implode(' AND ', $aWhere); 487 | 488 | $res = Database::getInstance()->execute($sQuery); 489 | $value = Database::getInstance()->fetch($res); 490 | 491 | if (!empty($value)) { 492 | if (!empty($iId)) { 493 | if ($value->{$this->registryIdField} == $iId) { 494 | return true; 495 | } 496 | else { 497 | return false; 498 | } 499 | } 500 | if ($getId) { 501 | return $value->{$this->registryIdField}; 502 | } 503 | else { 504 | return true; 505 | } 506 | } 507 | else { 508 | if (!empty($iId)) { 509 | return true; 510 | } 511 | } 512 | 513 | return false; 514 | } 515 | 516 | /** 517 | * Metoda dodaje nowy rekord do bazy. 518 | * 519 | * @param array $aParams Tablica z danymi do dodania do bazy 520 | * @return int Identyfikator ostatnio dodanego rekordu 521 | * @throws 522 | * @since 2012-06-18 523 | * @version 1.0 524 | */ 525 | public function add($aParams) 526 | { 527 | $aSet = array(); 528 | $aValues = array(); 529 | 530 | if (empty($this->tableFields)) { 531 | throw new \Exception('Brak tableFields dla modelu'); 532 | } 533 | 534 | foreach ($aParams as $sKey => $mValue) { 535 | if ($mValue === null) { 536 | continue; 537 | } 538 | if (in_array($sKey, $this->tableFields)) { 539 | $aSet[] = '`' . $sKey . '`'; 540 | switch (gettype($mValue)) { 541 | case 'integer': 542 | case 'boolean': 543 | $aValues[] = $mValue; 544 | break; 545 | case 'string': 546 | $aValues[] = "'$mValue'"; 547 | } 548 | } 549 | } 550 | 551 | $sSet = implode(',', $aSet); 552 | $sValues = implode(',', $aValues); 553 | 554 | $sSql = 'INSERT INTO ' . $this->tableName . ' (' . $sSet . ') VALUES (' . $sValues . ')'; 555 | $oDatabase = Database::getInstance(); 556 | $oDatabase->execute($sSql); 557 | $iLastInsertId = $oDatabase->lastUsedID(); 558 | 559 | return $iLastInsertId; 560 | } 561 | 562 | /** 563 | * Metoda edytuje dane w tabeli. 564 | * 565 | * @param array $aParams Tablica z danymi do edycji bazy 566 | * @param int $$iId Identyfikator rekordu 567 | * @return int Identyfikator ostatnio zedytowanego rekordu 568 | * @throws 569 | * @since 2012-06-19 570 | * @version 1.0 571 | */ 572 | public function edit($aParams, $iId) 573 | { 574 | $aUpdate = array(); 575 | 576 | foreach ($aParams as $sKey => $mValue) { 577 | if ($mValue === null) { 578 | continue; 579 | } 580 | if (in_array($sKey, $this->tableFields)) { 581 | switch (gettype($mValue)) { 582 | case 'integer': 583 | case 'boolean': 584 | $aUpdate[$sKey] = '`' . $sKey . '`' . '=' . $mValue; 585 | break; 586 | case 'string': 587 | $aUpdate[$sKey] = '`' . $sKey . '`' . '=' . "'$mValue'"; 588 | } 589 | } 590 | } 591 | 592 | $sUpdate = implode(',', $aUpdate); 593 | 594 | $sSql = 'UPDATE ' . $this->tableName . ' SET ' . $sUpdate . 595 | ' WHERE ' . $this->registryIdField . '=' . $iId; 596 | $oDatabase = Database::getInstance(); 597 | $oDatabase->execute($sSql); 598 | $iLastInsertId = $oDatabase->lastUsedID(); 599 | 600 | /* 601 | * Zrzuć cache 602 | */ 603 | $this->dropCache($iId); 604 | 605 | return $iLastInsertId; 606 | } 607 | 608 | } -------------------------------------------------------------------------------- /diagram.ps: -------------------------------------------------------------------------------- 1 | %!PS-Adobe-3.0 2 | %%Creator: gEDA gschem 1.6.1-20100214-22-ga30f00b 3 | %%CreationDate: Mon Jul 1 10:36:51 2013 4 | %%Title: /home/pawel/Projects/raspberry_temperature_log/diagram.sch 5 | %%Author: (null) 6 | %%BoundingBox: 0 0 612 792 7 | %%Orientation: Landscape 8 | %%Pages: 1 9 | %%Endcomments 10 | %%BeginProlog 11 | % Prolog for gEDA, define all the functions needed for rendering 12 | % schematics on Postscript devices 13 | 14 | 15 | % Draw a line from the second coordinate to the first 16 | % x2 y2 x1 y1 width line - 17 | /line { 18 | setlinewidth 19 | % pop off first element and moveto 20 | moveto 21 | % pop off remaining elements and draw a line segment 22 | lineto 23 | % draw it 24 | stroke 25 | } bind def 26 | 27 | 28 | % Draw a dot 29 | % x y r dot - 30 | /dot { 31 | 0 360 arc fill 32 | } bind def 33 | 34 | % Draw a dot-dashed line, a bunch of lined segments, 35 | % if the array element only has length two, draw a dot. 36 | % [ [x2 y2 x1 y1] [x4 y4 x3 y3] [x5 y5] ... ] width dashed - 37 | /width 0 def 38 | /dashed { 39 | dup 2.0 div /width exch def 40 | setlinewidth 41 | % pop off each line segment and draw it as a dot or as a line 42 | { 43 | aload length 2 gt 44 | { moveto lineto stroke} 45 | { width dot } ifelse 46 | } forall 47 | } bind def 48 | 49 | % Draw an arc segment 50 | % x y r ang1 ang2 width darc - 51 | /darc { 52 | setlinewidth 53 | arc stroke 54 | } bind def 55 | 56 | % Draw a series of arc segment bits, if the array element only has a single 57 | % element in it, draw a dot. 58 | % [ [sa1 ea1] [sa2 ea2] ... ] x y r width dashedarc - 59 | /x 0 def 60 | /y 0 def 61 | /dashedarc { 62 | dup /width exch def 63 | setlinewidth 64 | /r exch def 65 | /y exch def 66 | /x exch def 67 | { aload length 1 gt 68 | { 69 | % this element had two angles in it 70 | % extract start and stop angles 71 | x y r % drop x y and r onto stack 72 | % at this point we have: sa ea x y r 73 | % we need x y r sa ea 74 | % so.. 75 | 5 -2 roll 76 | % and add it to the current path, and draw it 77 | arc stroke 78 | } { 79 | % this element only had one angle in it, place a 80 | % filled dot at the appropriate place 81 | % compute center point of the arc using the angle 82 | % that is on the top of the stack 83 | dup % angle angle 84 | cos r mul x add % angle x 85 | exch % x angle 86 | sin r mul y add % x y 87 | width % x y width/2 88 | dot % draw the dot 89 | } ifelse 90 | } forall 91 | 92 | % Now draw it 93 | stroke 94 | } bind def 95 | 96 | % Draw a box 97 | % width height x y linethickness box - 98 | /box { 99 | setlinewidth 100 | moveto 101 | exch dup 0 rlineto % w h, h w w 0 -- Draw bottom line 102 | exch 0 exch rlineto % h w, w h 0, w 0 h -- Draw right line 103 | neg 0 rlineto % w, -w 0 -- Draw Top line 104 | closepath % finish and draw it 105 | stroke 106 | } bind def 107 | 108 | % Draw a filled box 109 | % width height x y fbox - 110 | /fbox { 111 | moveto 112 | exch dup 0 rlineto 113 | exch 0 exch rlineto 114 | neg 0 rlineto 115 | closepath 116 | fill 117 | } bind def 118 | 119 | % Font reincoding utilities 120 | 121 | % ISOLatin1Encoding, extended with remaining uncoded glyphs 122 | /ISOLatin1Extended [ 123 | /.notdef /Lslash /lslash /OE /oe /Scaron /scaron /Zcaron /zcaron 124 | /Ydieresis /trademark /bullet /dagger /daggerdbl /ellipsis /emdash 125 | /endash /fi /fl /florin /fraction /guilsinglleft /guilsinglright 126 | /perthousand /quotedblbase /quotedblleft /quotedblright 127 | /quotesinglbase /quotesingle /.notdef /.notdef /.notdef /space 128 | /exclam /quotedbl /numbersign /dollar /percent /ampersand 129 | /quoteright /parenleft /parenright /asterisk /plus /comma /minus 130 | /period /slash /zero /one /two /three /four /five /six /seven /eight 131 | /nine /colon /semicolon /less /equal /greater /question /at /A /B /C 132 | /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z 133 | /bracketleft /backslash /bracketright /asciicircum /underscore 134 | /quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p /q /r /s 135 | /t /u /v /w /x /y /z /braceleft /bar /braceright /asciitilde 136 | /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef 137 | /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef 138 | /.notdef /.notdef /.notdef /dotlessi /grave /acute /circumflex 139 | /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla 140 | /.notdef /hungarumlaut /ogonek /caron /space /exclamdown /cent 141 | /sterling /currency /yen /brokenbar /section /dieresis /copyright 142 | /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron 143 | /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph 144 | /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright 145 | /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute 146 | /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute 147 | /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth 148 | /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply 149 | /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn 150 | /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring 151 | /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave 152 | /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute 153 | /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute 154 | /ucircumflex /udieresis /yacute /thorn /ydieresis 155 | ] def 156 | 157 | % `new-font-name' `encoding-vector' `old-font-name' RE - 158 | /RE { 159 | findfont 160 | dup maxlength dict begin { 161 | 1 index /FID ne { def } { pop pop } ifelse 162 | } forall 163 | /Encoding exch def 164 | dup /FontName exch def 165 | currentdict end definefont pop 166 | } bind def 167 | 168 | % Text handling functions, select the font and scale it, then we need 169 | % only to apply the appropriate transformations to get the text 170 | % justified into the right spots. The bad thing here is that we don't 171 | % do any kerning, so the output may look a bit strange. 172 | 173 | % compute the height of one character and return lly and ury 174 | % (char) charheight lly ury 175 | /charheight { 176 | gsave % push graphics state 177 | newpath % clear current path 178 | 0 0 moveto % Set current point 179 | false charpath % get path 180 | flattenpath % flatten path 181 | pathbbox % stack = llx lly urx ury 182 | exch pop % stack = llx lly ury 183 | 3 -1 roll pop % stack = lly ury 184 | grestore % pop graphics state 185 | } bind def 186 | 187 | % compute the height of a string, one character at a time 188 | % (string) stringheight lly ury 189 | /lly 0.0 def 190 | /ury 0.0 def 191 | 192 | /stringheight { 193 | /lly 0.0 def % initial value of heightmin 194 | /ury 0.0 def % initial value of heightmax 195 | { % work through string 196 | ( ) dup 0 4 -1 roll put % create one character string 197 | charheight % measure it's height 198 | dup ury gt { % if ury gt heightmax 199 | /ury exch def % update with new value 200 | } { 201 | pop % else discard ury 202 | } ifelse 203 | dup lly lt { % if lly lt heightmin 204 | /lly exch def % update with new value 205 | } { 206 | pop % else discard lly 207 | } ifelse 208 | } forall 209 | lly ury % Return the results 210 | } bind def 211 | 212 | % calculate the string width taking into account the escapes. 213 | /mystrx 0.0 def 214 | /mystry 0.0 def 215 | /mystresc false def 216 | 217 | /mystringwidth { 218 | /mystrx 0.0 def 219 | /mystry 0.0 def 220 | /mystresc false def 221 | { % work through string 222 | % did we process the escape character last? 223 | mystresc { 224 | % last character was escape 225 | % handle the escape 226 | % is it an _ = 95? 227 | dup 95 eq { 228 | pop % we don't need the character anymore 229 | % toggle drawing overbars 230 | 0.0 0.0 % make it like it never happened... 231 | } { 232 | % otherwise measure the character 233 | (\\ ) dup 1 4 -1 roll put % count a \ and the character 234 | stringwidth 235 | } ifelse 236 | % and reset the flag 237 | /mystresc false def 238 | } { 239 | % last character was not escape 240 | % is this escape 241 | dup 92 eq { 242 | % yes, escape character, set flag 243 | /mystresc true def 244 | pop % drop character 245 | 0.0 0.0 % make like this character has no width and height 246 | } { 247 | ( ) dup 0 4 -1 roll put % create one character string 248 | stringwidth % measure it's height/width 249 | } ifelse 250 | } ifelse 251 | % accumulate x and y movements 252 | mystry add /mystry exch def 253 | mystrx add /mystrx exch def 254 | } forall 255 | mystrx mystry % drop results on stack 256 | } bind def 257 | 258 | % Render a string with overbars 259 | % 260 | /escaped false def 261 | /drawoverbar false def 262 | /fontsize 0.0 def 263 | 264 | %string1 string2 append - 265 | /append { 266 | 2 copy length exch length add % find new length 267 | string dup % string1 string2 string string 268 | 4 2 roll % string string string1 string2 269 | 2 index 0 3 index 270 | % string string string1 string2 string 0 string1 271 | putinterval % string string string1 string2 272 | exch length exch putinterval 273 | } bind def 274 | 275 | % If drawoverbar is set, draw a line of the same length as the given string 276 | % string overbarshowline - 277 | /overbarshowline { 278 | % print overbar if necessary 279 | stringwidth pop 0 280 | drawoverbar { 281 | rlineto 282 | gsave stroke grestore 283 | } { 284 | rmoveto 285 | } ifelse 286 | } bind def 287 | 288 | % Draws overbars for the given string, then shows the string itself 289 | % string overbarshow 290 | /overbarshow { 291 | /overbarshowacc () def 292 | /overbarshowtxt () def 293 | 294 | gsave 295 | fontsize 10.0 div setlinewidth 296 | 0 fontsize rmoveto % move to (0,overbarheight) 297 | 298 | { % work through string 299 | escaped { 300 | % the last character was the escape 301 | % handle the escape 302 | % is it an _ = 95? 303 | dup 95 eq { 304 | pop % we don't need the character anymore 305 | overbarshowacc overbarshowline 306 | % toggle drawing overbars 307 | /drawoverbar drawoverbar not def 308 | 309 | % Append the contents off the accumulator to the text 310 | % string we're eventually going to show 311 | /overbarshowtxt overbarshowtxt overbarshowacc append def 312 | 313 | % clear accumulator 314 | /overbarshowacc () def 315 | } { 316 | % add to accumulator 317 | (\\ ) dup 1 4 -1 roll put 318 | overbarshowacc exch append 319 | /overbarshowacc exch def 320 | } ifelse 321 | % and reset the flag 322 | /escaped false def 323 | } { 324 | % check for escape character \ = 92 325 | dup 92 eq { 326 | % yes, escape character, set flag 327 | /escaped true def 328 | pop % drop character 329 | } { 330 | % add to accumulator 331 | ( ) dup 0 4 -1 roll put 332 | overbarshowacc exch append 333 | /overbarshowacc exch def 334 | } ifelse 335 | } ifelse 336 | } forall 337 | % Catch any leftovers 338 | overbarshowacc overbarshowline 339 | overbarshowtxt overbarshowacc append 340 | 341 | grestore 342 | show 343 | } bind def 344 | 345 | % 346 | % hcenter rjustify vcenter vjustify spacing [(line1) (line2) ... ] rot x y size text - 347 | /stringw 0.0 def 348 | /stringh 0.0 def 349 | /spacing 0.0 def 350 | /strings [ ] def 351 | /stringtxt ( ) def 352 | /stringcount 0 def 353 | /rot 0.0 def 354 | 355 | /text { 356 | gsave % save state for later 357 | /drawoverbar false def % start by not drawing overbars 358 | 359 | dup /fontsize exch def % save font size for corrections later 360 | % do font selection 361 | /gEDAFont findfont 362 | exch scalefont 363 | setfont 364 | 365 | % set up coordinates 366 | translate % move origin to given point 367 | rotate % rotate so that text is drawn 368 | 0 0 moveto 369 | dup length /stringcount exch def % Get number of strings 370 | /strings exch def % save strings 371 | /spacing exch def 372 | % do we have more than 1 string to render? 373 | stringcount 1 eq { 374 | /stringtxt strings aload pop def % get the string 375 | /stringw stringtxt mystringwidth pop neg def % get the -width 376 | /stringh stringtxt stringheight exch pop neg def% get the -height 377 | 378 | % First do vertical calculations 379 | % hcenter rjustify vcenter vjustify 380 | % vertical justification 381 | { 0 stringh rmoveto } if 382 | % vertical center 383 | { 0 stringh 0.3571425 mul rmoveto } if % not 0.5, so that 384 | % it looks nicer 385 | % Then do horizontal calculations 386 | % right justify 387 | { stringw 0 rmoveto } if 388 | % center 389 | { stringw 2.0 div 0 rmoveto } if 390 | % Draw the text 391 | stringtxt overbarshow 392 | } { 393 | % More than one line, compute bounding box for the text 394 | 395 | % vertical height, don't use the actual hieght of the characters 396 | % assume that the user wants to make the baselines line up with two 397 | % text boxes placed side by side 398 | /stringh stringcount spacing mul neg def 399 | % Now figure out horizontal size, this amounts to keeping track 400 | % of the longest string 401 | /stringw 0.0 def 402 | strings { 403 | mystringwidth pop 404 | dup stringw gt { 405 | /stringw exch def 406 | } { 407 | pop 408 | } ifelse 409 | } forall 410 | /stringw stringw neg def % get the -width 411 | 412 | % First do vertical calculations 413 | % hcenter rjustify vcenter vjustify 414 | % vertical justification 415 | { 0 stringh fontsize add rmoveto } if 416 | % vertical center 417 | { 0 stringh 0.5 mul rmoveto } if 418 | % Then do horizontal calculations 419 | % right justify 420 | { stringw 0 rmoveto } if 421 | % center 422 | { stringw 2.0 div 0 rmoveto } if 423 | % now move up to the first line and begin rendering 424 | 0 stringcount 1 sub spacing mul rmoveto 425 | strings { 426 | gsave % Save starting point 427 | overbarshow % render the text 428 | grestore 429 | 0 spacing neg rmoveto 430 | } forall 431 | } ifelse 432 | grestore % Restore old state 433 | } bind def 434 | 435 | 436 | %%EndProlog 437 | %%Page: 1 1 438 | /gEDAFont ISOLatin1Extended /Helvetica RE 439 | 2 setlinecap 440 | 0.072000 0.072000 scale 441 | 7485 500 translate 90 rotate 442 | 0.588235 0.588235 scale 443 | -40000 -40000 translate 444 | gsave 445 | 40000 40000 57000 40000 10 line 446 | 57000 40000 57000 51000 10 line 447 | 57000 51000 40000 51000 10 line 448 | 40000 51000 40000 40000 10 line 449 | 52900 40600 52900 40000 10 line 450 | gsave 451 | false false false false 208.000000 [(FILE:) ] 0 49500 40400 144.444443 text 452 | grestore 453 | gsave 454 | false false false false 208.000000 [(REVISION:) ] 0 53000 40400 144.444443 text 455 | grestore 456 | gsave 457 | false false false false 208.000000 [(DRAWN BY: ) ] 0 53000 40100 144.444443 text 458 | grestore 459 | gsave 460 | false false false false 208.000000 [(PAGE) ] 0 49500 40100 144.444443 text 461 | grestore 462 | gsave 463 | false false false false 208.000000 [(OF) ] 0 51200 40100 144.444443 text 464 | grestore 465 | gsave 466 | false false false false 208.000000 [(TITLE) ] 0 49500 40700 144.444443 text 467 | grestore 468 | 49400 40000 57000 40000 10 line 469 | 57000 40000 57000 41400 10 line 470 | 57000 41400 49400 41400 10 line 471 | 49400 41400 49400 40000 10 line 472 | 49400 40600 57000 40600 10 line 473 | grestore 474 | gsave 475 | 42100 50000 42300 50000 10 line 476 | 41500 50100 41500 49900 10 line 477 | 41500 50100 42000 50100 10 line 478 | 42000 50100 42100 50000 10 line 479 | 42100 50000 42000 49900 10 line 480 | 42000 49900 41500 49900 10 line 481 | grestore 482 | gsave 483 | 42100 47000 42300 47000 10 line 484 | 41500 47100 41500 46900 10 line 485 | 41500 47100 42000 47100 10 line 486 | 42000 47100 42100 47000 10 line 487 | 42100 47000 42000 46900 10 line 488 | 42000 46900 41500 46900 10 line 489 | grestore 490 | gsave 491 | 42100 48500 42300 48500 10 line 492 | 41500 48600 41500 48400 10 line 493 | 41500 48600 42000 48600 10 line 494 | 42000 48600 42100 48500 10 line 495 | 42100 48500 42000 48400 10 line 496 | 42000 48400 41500 48400 10 line 497 | grestore 498 | gsave 499 | 45900 50000 45700 50000 10 line 500 | 46500 49900 46500 50100 10 line 501 | 46500 49900 46000 49900 10 line 502 | 46000 49900 45900 50000 10 line 503 | 45900 50000 46000 50100 10 line 504 | 46000 50100 46500 50100 10 line 505 | grestore 506 | gsave 507 | 45900 48500 45700 48500 10 line 508 | 46500 48400 46500 48600 10 line 509 | 46500 48400 46000 48400 10 line 510 | 46000 48400 45900 48500 10 line 511 | 45900 48500 46000 48600 10 line 512 | 46000 48600 46500 48600 10 line 513 | grestore 514 | gsave 515 | 45900 47000 45700 47000 10 line 516 | 46500 46900 46500 47100 10 line 517 | 46500 46900 46000 46900 10 line 518 | 46000 46900 45900 47000 10 line 519 | 45900 47000 46000 47100 10 line 520 | 46000 47100 46500 47100 10 line 521 | grestore 522 | gsave 523 | false false false false 260.000000 [(Raspberry Pi) ] 0 41300 50400 180.555557 text 524 | grestore 525 | gsave 526 | false false false false 260.000000 [(DHT11) ] 0 45900 50300 180.555557 text 527 | grestore 528 | gsave 529 | false false false false 260.000000 [(Vcc) ] 0 46700 50000 180.555557 text 530 | grestore 531 | gsave 532 | false false false false 260.000000 [(Sig) ] 0 46700 48500 180.555557 text 533 | grestore 534 | gsave 535 | false false false false 260.000000 [(GND) ] 0 46700 47000 180.555557 text 536 | grestore 537 | gsave 538 | false false false false 260.000000 [(3.3V [1]) ] 0 40800 50000 180.555557 text 539 | grestore 540 | gsave 541 | false false false false 260.000000 [(GND [6]) ] 0 40700 47000 180.555557 text 542 | grestore 543 | gsave 544 | false false false false 260.000000 [(GPIO4 [7]) ] 0 40600 48600 180.555557 text 545 | grestore 546 | 42300 50000 45700 50000 10 line 547 | gsave 548 | 42700 49500 42900 49400 10 line 549 | 42900 49400 42700 49300 10 line 550 | 42700 49300 42900 49200 10 line 551 | 42900 49200 42700 49100 10 line 552 | 42700 49500 42900 49600 10 line 553 | 42900 49600 42800 49650 10 line 554 | 42800 49800 42800 49650 10 line 555 | 42800 48900 42800 49052 10 line 556 | 42700 49101 42800 49050 10 line 557 | grestore 558 | gsave 559 | false false false false 260.000000 [(10k) ] 90 42600 49100 180.555557 text 560 | grestore 561 | 42800 49800 42800 50000 10 line 562 | 42300 48500 45700 48500 10 line 563 | 42800 48900 42800 48500 10 line 564 | 42300 47000 45700 47000 10 line 565 | newpath 566 | 42800 50000 567 | 25 568 | 0 360 arc 569 | fill 570 | newpath 571 | 42800 50000 572 | 25 573 | 0 360 arc 574 | fill 575 | newpath 576 | 42800 50000 577 | 25 578 | 0 360 arc 579 | fill 580 | newpath 581 | 42800 48500 582 | 25 583 | 0 360 arc 584 | fill 585 | newpath 586 | 42800 48500 587 | 25 588 | 0 360 arc 589 | fill 590 | newpath 591 | 42800 48500 592 | 25 593 | 0 360 arc 594 | fill 595 | showpage 596 | %%End 597 | -------------------------------------------------------------------------------- /website/css/docs.css: -------------------------------------------------------------------------------- 1 | /* Add additional stylesheets below 2 | -------------------------------------------------- */ 3 | /* 4 | Bootstrap's documentation styles 5 | Special styles for presenting Bootstrap's documentation and examples 6 | */ 7 | 8 | 9 | /* Body and structure 10 | -------------------------------------------------- */ 11 | 12 | body { 13 | position: relative; 14 | padding-top: 40px; 15 | } 16 | 17 | /* Code in headings */ 18 | h3 code { 19 | font-size: 14px; 20 | font-weight: normal; 21 | } 22 | 23 | 24 | /* Sections 25 | -------------------------------------------------- */ 26 | 27 | /* padding for in-page bookmarks and fixed navbar */ 28 | section { 29 | padding-top: 30px; 30 | } 31 | section > .page-header, 32 | section > .lead { 33 | color: #5a5a5a; 34 | } 35 | section > ul li { 36 | margin-bottom: 5px; 37 | } 38 | 39 | /* Separators (hr) */ 40 | .bs-docs-separator { 41 | margin: 40px 0 39px; 42 | } 43 | 44 | /* Faded out hr */ 45 | hr.soften { 46 | height: 1px; 47 | margin: 70px 0; 48 | background-image: -webkit-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,.1), rgba(0,0,0,0)); 49 | background-image: -moz-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,.1), rgba(0,0,0,0)); 50 | background-image: -ms-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,.1), rgba(0,0,0,0)); 51 | background-image: -o-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,.1), rgba(0,0,0,0)); 52 | border: 0; 53 | } 54 | 55 | 56 | 57 | /* Jumbotrons 58 | -------------------------------------------------- */ 59 | 60 | /* Base class 61 | ------------------------- */ 62 | .jumbotron { 63 | position: relative; 64 | padding: 40px 0; 65 | color: #fff; 66 | text-align: center; 67 | text-shadow: 0 1px 3px rgba(0,0,0,.4), 0 0 30px rgba(0,0,0,.075); 68 | background: #020031; /* Old browsers */ 69 | background: -moz-linear-gradient(45deg, #020031 0%, #6d3353 100%); /* FF3.6+ */ 70 | background: -webkit-gradient(linear, left bottom, right top, color-stop(0%,#020031), color-stop(100%,#6d3353)); /* Chrome,Safari4+ */ 71 | background: -webkit-linear-gradient(45deg, #020031 0%,#6d3353 100%); /* Chrome10+,Safari5.1+ */ 72 | background: -o-linear-gradient(45deg, #020031 0%,#6d3353 100%); /* Opera 11.10+ */ 73 | background: -ms-linear-gradient(45deg, #020031 0%,#6d3353 100%); /* IE10+ */ 74 | background: linear-gradient(45deg, #020031 0%,#6d3353 100%); /* W3C */ 75 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#020031', endColorstr='#6d3353',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */ 76 | -webkit-box-shadow: inset 0 3px 7px rgba(0,0,0,.2), inset 0 -3px 7px rgba(0,0,0,.2); 77 | -moz-box-shadow: inset 0 3px 7px rgba(0,0,0,.2), inset 0 -3px 7px rgba(0,0,0,.2); 78 | box-shadow: inset 0 3px 7px rgba(0,0,0,.2), inset 0 -3px 7px rgba(0,0,0,.2); 79 | } 80 | .jumbotron h1 { 81 | font-size: 80px; 82 | font-weight: bold; 83 | letter-spacing: -1px; 84 | line-height: 1; 85 | } 86 | .jumbotron p { 87 | font-size: 24px; 88 | font-weight: 300; 89 | line-height: 1.25; 90 | margin-bottom: 30px; 91 | } 92 | 93 | /* Link styles (used on .masthead-links as well) */ 94 | .jumbotron a { 95 | color: #fff; 96 | color: rgba(255,255,255,.5); 97 | -webkit-transition: all .2s ease-in-out; 98 | -moz-transition: all .2s ease-in-out; 99 | transition: all .2s ease-in-out; 100 | } 101 | .jumbotron a:hover { 102 | color: #fff; 103 | text-shadow: 0 0 10px rgba(255,255,255,.25); 104 | } 105 | 106 | /* Download button */ 107 | .masthead .btn { 108 | padding: 19px 24px; 109 | font-size: 24px; 110 | font-weight: 200; 111 | color: #fff; /* redeclare to override the `.jumbotron a` */ 112 | border: 0; 113 | -webkit-border-radius: 6px; 114 | -moz-border-radius: 6px; 115 | border-radius: 6px; 116 | -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); 117 | -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); 118 | box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); 119 | -webkit-transition: none; 120 | -moz-transition: none; 121 | transition: none; 122 | } 123 | .masthead .btn:hover { 124 | -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); 125 | -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); 126 | box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); 127 | } 128 | .masthead .btn:active { 129 | -webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.1); 130 | -moz-box-shadow: inset 0 2px 4px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.1); 131 | box-shadow: inset 0 2px 4px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.1); 132 | } 133 | 134 | 135 | /* Pattern overlay 136 | ------------------------- */ 137 | .jumbotron .container { 138 | position: relative; 139 | z-index: 2; 140 | } 141 | .jumbotron:after { 142 | content: ''; 143 | display: block; 144 | position: absolute; 145 | top: 0; 146 | right: 0; 147 | bottom: 0; 148 | left: 0; 149 | background: url(../img/bs-docs-masthead-pattern.png) repeat center center; 150 | opacity: .4; 151 | } 152 | 153 | /* Masthead (docs home) 154 | ------------------------- */ 155 | .masthead { 156 | padding: 70px 0 80px; 157 | margin-bottom: 0; 158 | color: #fff; 159 | } 160 | .masthead h1 { 161 | font-size: 120px; 162 | line-height: 1; 163 | letter-spacing: -2px; 164 | } 165 | .masthead p { 166 | font-size: 40px; 167 | font-weight: 200; 168 | line-height: 1.25; 169 | } 170 | 171 | /* Textual links in masthead */ 172 | .masthead-links { 173 | margin: 0; 174 | list-style: none; 175 | } 176 | .masthead-links li { 177 | display: inline; 178 | padding: 0 10px; 179 | color: rgba(255,255,255,.25); 180 | } 181 | 182 | /* Social proof buttons from GitHub & Twitter */ 183 | .bs-docs-social { 184 | padding: 15px 0; 185 | text-align: center; 186 | background-color: #f5f5f5; 187 | border-top: 1px solid #fff; 188 | border-bottom: 1px solid #ddd; 189 | } 190 | 191 | /* Quick links on Home */ 192 | .bs-docs-social-buttons { 193 | margin-left: 0; 194 | margin-bottom: 0; 195 | padding-left: 0; 196 | list-style: none; 197 | } 198 | .bs-docs-social-buttons li { 199 | display: inline-block; 200 | padding: 5px 8px; 201 | line-height: 1; 202 | *display: inline; 203 | *zoom: 1; 204 | } 205 | 206 | /* Subhead (other pages) 207 | ------------------------- */ 208 | .subhead { 209 | text-align: left; 210 | border-bottom: 1px solid #ddd; 211 | } 212 | .subhead h1 { 213 | font-size: 60px; 214 | } 215 | .subhead p { 216 | margin-bottom: 20px; 217 | } 218 | .subhead .navbar { 219 | display: none; 220 | } 221 | 222 | 223 | 224 | /* Marketing section of Overview 225 | -------------------------------------------------- */ 226 | 227 | .marketing { 228 | text-align: center; 229 | color: #5a5a5a; 230 | } 231 | .marketing h1 { 232 | margin: 60px 0 10px; 233 | font-size: 60px; 234 | font-weight: 200; 235 | line-height: 1; 236 | letter-spacing: -1px; 237 | } 238 | .marketing h2 { 239 | font-weight: 200; 240 | margin-bottom: 5px; 241 | } 242 | .marketing p { 243 | font-size: 16px; 244 | line-height: 1.5; 245 | } 246 | .marketing .marketing-byline { 247 | margin-bottom: 40px; 248 | font-size: 20px; 249 | font-weight: 300; 250 | line-height: 1.25; 251 | color: #999; 252 | } 253 | .marketing img { 254 | display: block; 255 | margin: 0 auto 30px; 256 | } 257 | 258 | 259 | 260 | /* Footer 261 | -------------------------------------------------- */ 262 | 263 | .footer { 264 | padding: 20px 0; 265 | margin-top: 20px; 266 | border-top: 1px solid #e5e5e5; 267 | background-color: #f5f5f5; 268 | } 269 | .footer p { 270 | margin-bottom: 0; 271 | color: #777; 272 | } 273 | .footer-links { 274 | margin: 10px 0; 275 | } 276 | .footer-links li { 277 | display: inline; 278 | padding: 0 2px; 279 | } 280 | .footer-links li:first-child { 281 | padding-left: 0; 282 | } 283 | 284 | 285 | 286 | /* Special grid styles 287 | -------------------------------------------------- */ 288 | 289 | .show-grid { 290 | margin-top: 10px; 291 | margin-bottom: 20px; 292 | } 293 | .show-grid [class*="span"] { 294 | background-color: #eee; 295 | text-align: center; 296 | -webkit-border-radius: 3px; 297 | -moz-border-radius: 3px; 298 | border-radius: 3px; 299 | min-height: 40px; 300 | line-height: 40px; 301 | } 302 | .show-grid:hover [class*="span"] { 303 | background: #ddd; 304 | } 305 | .show-grid .show-grid { 306 | margin-top: 0; 307 | margin-bottom: 0; 308 | } 309 | .show-grid .show-grid [class*="span"] { 310 | background-color: #ccc; 311 | } 312 | 313 | 314 | 315 | /* Mini layout previews 316 | -------------------------------------------------- */ 317 | .mini-layout { 318 | border: 1px solid #ddd; 319 | -webkit-border-radius: 6px; 320 | -moz-border-radius: 6px; 321 | border-radius: 6px; 322 | -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.075); 323 | -moz-box-shadow: 0 1px 2px rgba(0,0,0,.075); 324 | box-shadow: 0 1px 2px rgba(0,0,0,.075); 325 | } 326 | .mini-layout, 327 | .mini-layout .mini-layout-body, 328 | .mini-layout.fluid .mini-layout-sidebar { 329 | height: 300px; 330 | } 331 | .mini-layout { 332 | margin-bottom: 20px; 333 | padding: 9px; 334 | } 335 | .mini-layout div { 336 | -webkit-border-radius: 3px; 337 | -moz-border-radius: 3px; 338 | border-radius: 3px; 339 | } 340 | .mini-layout .mini-layout-body { 341 | background-color: #dceaf4; 342 | margin: 0 auto; 343 | width: 70%; 344 | } 345 | .mini-layout.fluid .mini-layout-sidebar, 346 | .mini-layout.fluid .mini-layout-header, 347 | .mini-layout.fluid .mini-layout-body { 348 | float: left; 349 | } 350 | .mini-layout.fluid .mini-layout-sidebar { 351 | background-color: #bbd8e9; 352 | width: 20%; 353 | } 354 | .mini-layout.fluid .mini-layout-body { 355 | width: 77.5%; 356 | margin-left: 2.5%; 357 | } 358 | 359 | 360 | 361 | /* Download page 362 | -------------------------------------------------- */ 363 | 364 | .download .page-header { 365 | margin-top: 36px; 366 | } 367 | .page-header .toggle-all { 368 | margin-top: 5px; 369 | } 370 | 371 | /* Space out h3s when following a section */ 372 | .download h3 { 373 | margin-bottom: 5px; 374 | } 375 | .download-builder input + h3, 376 | .download-builder .checkbox + h3 { 377 | margin-top: 9px; 378 | } 379 | 380 | /* Fields for variables */ 381 | .download-builder input[type=text] { 382 | margin-bottom: 9px; 383 | font-family: Menlo, Monaco, "Courier New", monospace; 384 | font-size: 12px; 385 | color: #d14; 386 | } 387 | .download-builder input[type=text]:focus { 388 | background-color: #fff; 389 | } 390 | 391 | /* Custom, larger checkbox labels */ 392 | .download .checkbox { 393 | padding: 6px 10px 6px 25px; 394 | font-size: 13px; 395 | line-height: 18px; 396 | color: #555; 397 | background-color: #f9f9f9; 398 | -webkit-border-radius: 3px; 399 | -moz-border-radius: 3px; 400 | border-radius: 3px; 401 | cursor: pointer; 402 | } 403 | .download .checkbox:hover { 404 | color: #333; 405 | background-color: #f5f5f5; 406 | } 407 | .download .checkbox small { 408 | font-size: 12px; 409 | color: #777; 410 | } 411 | 412 | /* Variables section */ 413 | #variables label { 414 | margin-bottom: 0; 415 | } 416 | 417 | /* Giant download button */ 418 | .download-btn { 419 | margin: 36px 0 108px; 420 | } 421 | #download p, 422 | #download h4 { 423 | max-width: 50%; 424 | margin: 0 auto; 425 | color: #999; 426 | text-align: center; 427 | } 428 | #download h4 { 429 | margin-bottom: 0; 430 | } 431 | #download p { 432 | margin-bottom: 18px; 433 | } 434 | .download-btn .btn { 435 | display: block; 436 | width: auto; 437 | padding: 19px 24px; 438 | margin-bottom: 27px; 439 | font-size: 30px; 440 | line-height: 1; 441 | text-align: center; 442 | -webkit-border-radius: 6px; 443 | -moz-border-radius: 6px; 444 | border-radius: 6px; 445 | } 446 | 447 | 448 | 449 | /* Misc 450 | -------------------------------------------------- */ 451 | 452 | /* Make tables spaced out a bit more */ 453 | h2 + table, 454 | h3 + table, 455 | h4 + table, 456 | h2 + .row { 457 | margin-top: 5px; 458 | } 459 | 460 | /* Example sites showcase */ 461 | .example-sites { 462 | xmargin-left: 20px; 463 | } 464 | .example-sites img { 465 | max-width: 100%; 466 | margin: 0 auto; 467 | } 468 | 469 | .scrollspy-example { 470 | height: 200px; 471 | overflow: auto; 472 | position: relative; 473 | } 474 | 475 | 476 | /* Fake the :focus state to demo it */ 477 | .focused { 478 | border-color: rgba(82,168,236,.8); 479 | -webkit-box-shadow: inset 0 1px 3px rgba(0,0,0,.1), 0 0 8px rgba(82,168,236,.6); 480 | -moz-box-shadow: inset 0 1px 3px rgba(0,0,0,.1), 0 0 8px rgba(82,168,236,.6); 481 | box-shadow: inset 0 1px 3px rgba(0,0,0,.1), 0 0 8px rgba(82,168,236,.6); 482 | outline: 0; 483 | } 484 | 485 | /* For input sizes, make them display block */ 486 | .docs-input-sizes select, 487 | .docs-input-sizes input[type=text] { 488 | display: block; 489 | margin-bottom: 9px; 490 | } 491 | 492 | /* Icons 493 | ------------------------- */ 494 | .the-icons { 495 | margin-left: 0; 496 | list-style: none; 497 | } 498 | .the-icons li { 499 | float: left; 500 | width: 25%; 501 | line-height: 25px; 502 | } 503 | .the-icons i:hover { 504 | background-color: rgba(255,0,0,.25); 505 | } 506 | 507 | /* Example page 508 | ------------------------- */ 509 | .bootstrap-examples p { 510 | font-size: 13px; 511 | line-height: 18px; 512 | } 513 | .bootstrap-examples .thumbnail { 514 | margin-bottom: 9px; 515 | background-color: #fff; 516 | } 517 | 518 | 519 | 520 | /* Bootstrap code examples 521 | -------------------------------------------------- */ 522 | 523 | /* Base class */ 524 | .bs-docs-example { 525 | position: relative; 526 | margin: 15px 0; 527 | padding: 39px 19px 14px; 528 | *padding-top: 19px; 529 | background-color: #fff; 530 | border: 1px solid #ddd; 531 | -webkit-border-radius: 4px; 532 | -moz-border-radius: 4px; 533 | border-radius: 4px; 534 | } 535 | 536 | /* Echo out a label for the example */ 537 | .bs-docs-example:after { 538 | content: "Example"; 539 | position: absolute; 540 | top: -1px; 541 | left: -1px; 542 | padding: 3px 7px; 543 | font-size: 12px; 544 | font-weight: bold; 545 | background-color: #f5f5f5; 546 | border: 1px solid #ddd; 547 | color: #9da0a4; 548 | -webkit-border-radius: 4px 0 4px 0; 549 | -moz-border-radius: 4px 0 4px 0; 550 | border-radius: 4px 0 4px 0; 551 | } 552 | 553 | /* Remove spacing between an example and it's code */ 554 | .bs-docs-example + .prettyprint { 555 | margin-top: -20px; 556 | padding-top: 15px; 557 | } 558 | 559 | /* Tweak examples 560 | ------------------------- */ 561 | .bs-docs-example > p:last-child { 562 | margin-bottom: 0; 563 | } 564 | .bs-docs-example .table, 565 | .bs-docs-example .progress, 566 | .bs-docs-example .well, 567 | .bs-docs-example .alert, 568 | .bs-docs-example .hero-unit, 569 | .bs-docs-example .pagination, 570 | .bs-docs-example .navbar, 571 | .bs-docs-example > .nav, 572 | .bs-docs-example blockquote { 573 | margin-bottom: 5px; 574 | } 575 | .bs-docs-example .pagination { 576 | margin-top: 0; 577 | } 578 | .bs-navbar-top-example, 579 | .bs-navbar-bottom-example { 580 | z-index: 1; 581 | padding: 0; 582 | height: 90px; 583 | overflow: hidden; /* cut the drop shadows off */ 584 | } 585 | .bs-navbar-top-example .navbar-fixed-top, 586 | .bs-navbar-bottom-example .navbar-fixed-bottom { 587 | margin-left: 0; 588 | margin-right: 0; 589 | } 590 | .bs-navbar-top-example { 591 | -webkit-border-radius: 0 0 4px 4px; 592 | -moz-border-radius: 0 0 4px 4px; 593 | border-radius: 0 0 4px 4px; 594 | } 595 | .bs-navbar-top-example:after { 596 | top: auto; 597 | bottom: -1px; 598 | -webkit-border-radius: 0 4px 0 4px; 599 | -moz-border-radius: 0 4px 0 4px; 600 | border-radius: 0 4px 0 4px; 601 | } 602 | .bs-navbar-bottom-example { 603 | -webkit-border-radius: 4px 4px 0 0; 604 | -moz-border-radius: 4px 4px 0 0; 605 | border-radius: 4px 4px 0 0; 606 | } 607 | .bs-navbar-bottom-example .navbar { 608 | margin-bottom: 0; 609 | } 610 | form.bs-docs-example { 611 | padding-bottom: 19px; 612 | } 613 | 614 | /* Images */ 615 | .bs-docs-example-images img { 616 | margin: 10px; 617 | display: inline-block; 618 | } 619 | 620 | /* Tooltips */ 621 | .bs-docs-tooltip-examples { 622 | text-align: center; 623 | margin: 0 0 10px; 624 | list-style: none; 625 | } 626 | .bs-docs-tooltip-examples li { 627 | display: inline; 628 | padding: 0 10px; 629 | } 630 | 631 | /* Popovers */ 632 | .bs-docs-example-popover { 633 | padding-bottom: 24px; 634 | background-color: #f9f9f9; 635 | } 636 | .bs-docs-example-popover .popover { 637 | position: relative; 638 | display: block; 639 | float: left; 640 | width: 260px; 641 | margin: 20px; 642 | } 643 | 644 | 645 | 646 | /* Responsive docs 647 | -------------------------------------------------- */ 648 | 649 | /* Utility classes table 650 | ------------------------- */ 651 | .responsive-utilities th small { 652 | display: block; 653 | font-weight: normal; 654 | color: #999; 655 | } 656 | .responsive-utilities tbody th { 657 | font-weight: normal; 658 | } 659 | .responsive-utilities td { 660 | text-align: center; 661 | } 662 | .responsive-utilities td.is-visible { 663 | color: #468847; 664 | background-color: #dff0d8 !important; 665 | } 666 | .responsive-utilities td.is-hidden { 667 | color: #ccc; 668 | background-color: #f9f9f9 !important; 669 | } 670 | 671 | /* Responsive tests 672 | ------------------------- */ 673 | .responsive-utilities-test { 674 | margin-top: 5px; 675 | margin-left: 0; 676 | list-style: none; 677 | overflow: hidden; /* clear floats */ 678 | } 679 | .responsive-utilities-test li { 680 | position: relative; 681 | float: left; 682 | width: 25%; 683 | height: 43px; 684 | font-size: 14px; 685 | font-weight: bold; 686 | line-height: 43px; 687 | color: #999; 688 | text-align: center; 689 | border: 1px solid #ddd; 690 | -webkit-border-radius: 4px; 691 | -moz-border-radius: 4px; 692 | border-radius: 4px; 693 | } 694 | .responsive-utilities-test li + li { 695 | margin-left: 10px; 696 | } 697 | .responsive-utilities-test span { 698 | position: absolute; 699 | top: -1px; 700 | left: -1px; 701 | right: -1px; 702 | bottom: -1px; 703 | -webkit-border-radius: 4px; 704 | -moz-border-radius: 4px; 705 | border-radius: 4px; 706 | } 707 | .responsive-utilities-test span { 708 | color: #468847; 709 | background-color: #dff0d8; 710 | border: 1px solid #d6e9c6; 711 | } 712 | 713 | 714 | 715 | /* Sidenav for Docs 716 | -------------------------------------------------- */ 717 | 718 | .bs-docs-sidenav { 719 | width: 228px; 720 | margin: 30px 0 0; 721 | padding: 0; 722 | background-color: #fff; 723 | -webkit-border-radius: 6px; 724 | -moz-border-radius: 6px; 725 | border-radius: 6px; 726 | -webkit-box-shadow: 0 1px 4px rgba(0,0,0,.065); 727 | -moz-box-shadow: 0 1px 4px rgba(0,0,0,.065); 728 | box-shadow: 0 1px 4px rgba(0,0,0,.065); 729 | } 730 | .bs-docs-sidenav > li > a { 731 | display: block; 732 | width: 190px \9; 733 | margin: 0 0 -1px; 734 | padding: 8px 14px; 735 | border: 1px solid #e5e5e5; 736 | } 737 | .bs-docs-sidenav > li:first-child > a { 738 | -webkit-border-radius: 6px 6px 0 0; 739 | -moz-border-radius: 6px 6px 0 0; 740 | border-radius: 6px 6px 0 0; 741 | } 742 | .bs-docs-sidenav > li:last-child > a { 743 | -webkit-border-radius: 0 0 6px 6px; 744 | -moz-border-radius: 0 0 6px 6px; 745 | border-radius: 0 0 6px 6px; 746 | } 747 | .bs-docs-sidenav > .active > a { 748 | position: relative; 749 | z-index: 2; 750 | padding: 9px 15px; 751 | border: 0; 752 | text-shadow: 0 1px 0 rgba(0,0,0,.15); 753 | -webkit-box-shadow: inset 1px 0 0 rgba(0,0,0,.1), inset -1px 0 0 rgba(0,0,0,.1); 754 | -moz-box-shadow: inset 1px 0 0 rgba(0,0,0,.1), inset -1px 0 0 rgba(0,0,0,.1); 755 | box-shadow: inset 1px 0 0 rgba(0,0,0,.1), inset -1px 0 0 rgba(0,0,0,.1); 756 | } 757 | /* Chevrons */ 758 | .bs-docs-sidenav .icon-chevron-right { 759 | float: right; 760 | margin-top: 2px; 761 | margin-right: -6px; 762 | opacity: .25; 763 | } 764 | .bs-docs-sidenav > li > a:hover { 765 | background-color: #f5f5f5; 766 | } 767 | .bs-docs-sidenav a:hover .icon-chevron-right { 768 | opacity: .5; 769 | } 770 | .bs-docs-sidenav .active .icon-chevron-right, 771 | .bs-docs-sidenav .active a:hover .icon-chevron-right { 772 | background-image: url(../img/glyphicons-halflings-white.png); 773 | opacity: 1; 774 | } 775 | .bs-docs-sidenav.affix { 776 | top: 40px; 777 | } 778 | .bs-docs-sidenav.affix-bottom { 779 | position: absolute; 780 | top: auto; 781 | bottom: 270px; 782 | } 783 | 784 | 785 | 786 | 787 | /* Responsive 788 | -------------------------------------------------- */ 789 | 790 | /* Desktop large 791 | ------------------------- */ 792 | @media (min-width: 1200px) { 793 | .bs-docs-container { 794 | max-width: 970px; 795 | } 796 | .bs-docs-sidenav { 797 | width: 258px; 798 | } 799 | .bs-docs-sidenav > li > a { 800 | width: 230px \9; /* Override the previous IE8-9 hack */ 801 | } 802 | } 803 | 804 | /* Desktop 805 | ------------------------- */ 806 | @media (max-width: 980px) { 807 | /* Unfloat brand */ 808 | body > .navbar-fixed-top .brand { 809 | float: left; 810 | margin-left: 0; 811 | padding-left: 10px; 812 | padding-right: 10px; 813 | } 814 | 815 | /* Inline-block quick links for more spacing */ 816 | .quick-links li { 817 | display: inline-block; 818 | margin: 5px; 819 | } 820 | 821 | /* When affixed, space properly */ 822 | .bs-docs-sidenav { 823 | top: 0; 824 | margin-top: 30px; 825 | margin-right: 0; 826 | } 827 | } 828 | 829 | /* Tablet to desktop 830 | ------------------------- */ 831 | @media (min-width: 768px) and (max-width: 980px) { 832 | /* Remove any padding from the body */ 833 | body { 834 | padding-top: 0; 835 | } 836 | /* Widen masthead and social buttons to fill body padding */ 837 | .jumbotron { 838 | margin-top: -20px; /* Offset bottom margin on .navbar */ 839 | } 840 | /* Adjust sidenav width */ 841 | .bs-docs-sidenav { 842 | width: 166px; 843 | margin-top: 20px; 844 | } 845 | .bs-docs-sidenav.affix { 846 | top: 0; 847 | } 848 | } 849 | 850 | /* Tablet 851 | ------------------------- */ 852 | @media (max-width: 767px) { 853 | /* Remove any padding from the body */ 854 | body { 855 | padding-top: 0; 856 | } 857 | 858 | /* Widen masthead and social buttons to fill body padding */ 859 | .jumbotron { 860 | padding: 40px 20px; 861 | margin-top: -20px; /* Offset bottom margin on .navbar */ 862 | margin-right: -20px; 863 | margin-left: -20px; 864 | } 865 | .masthead h1 { 866 | font-size: 90px; 867 | } 868 | .masthead p, 869 | .masthead .btn { 870 | font-size: 24px; 871 | } 872 | .marketing .span4 { 873 | margin-bottom: 40px; 874 | } 875 | .bs-docs-social { 876 | margin: 0 -20px; 877 | } 878 | 879 | /* Space out the show-grid examples */ 880 | .show-grid [class*="span"] { 881 | margin-bottom: 5px; 882 | } 883 | 884 | /* Sidenav */ 885 | .bs-docs-sidenav { 886 | width: auto; 887 | margin-bottom: 20px; 888 | } 889 | .bs-docs-sidenav.affix { 890 | position: static; 891 | width: auto; 892 | top: 0; 893 | } 894 | 895 | /* Unfloat the back to top link in footer */ 896 | .footer { 897 | margin-left: -20px; 898 | margin-right: -20px; 899 | padding-left: 20px; 900 | padding-right: 20px; 901 | } 902 | .footer p { 903 | margin-bottom: 9px; 904 | } 905 | } 906 | 907 | /* Landscape phones 908 | ------------------------- */ 909 | @media (max-width: 480px) { 910 | /* Remove padding above jumbotron */ 911 | body { 912 | padding-top: 0; 913 | } 914 | 915 | /* Change up some type stuff */ 916 | h2 small { 917 | display: block; 918 | } 919 | 920 | /* Downsize the jumbotrons */ 921 | .jumbotron h1 { 922 | font-size: 45px; 923 | } 924 | .jumbotron p, 925 | .jumbotron .btn { 926 | font-size: 18px; 927 | } 928 | .jumbotron .btn { 929 | display: block; 930 | margin: 0 auto; 931 | } 932 | 933 | /* center align subhead text like the masthead */ 934 | .subhead h1, 935 | .subhead p { 936 | text-align: center; 937 | } 938 | 939 | /* Marketing on home */ 940 | .marketing h1 { 941 | font-size: 30px; 942 | } 943 | .marketing-byline { 944 | font-size: 18px; 945 | } 946 | 947 | /* center example sites */ 948 | .example-sites { 949 | margin-left: 0; 950 | } 951 | .example-sites > li { 952 | float: none; 953 | display: block; 954 | max-width: 280px; 955 | margin: 0 auto 18px; 956 | text-align: center; 957 | } 958 | .example-sites .thumbnail > img { 959 | max-width: 270px; 960 | } 961 | 962 | /* Do our best to make tables work in narrow viewports */ 963 | table code { 964 | white-space: normal; 965 | word-wrap: break-word; 966 | word-break: break-all; 967 | } 968 | 969 | /* Modal example */ 970 | .modal-example .modal { 971 | position: relative; 972 | top: auto; 973 | right: auto; 974 | bottom: auto; 975 | left: auto; 976 | } 977 | 978 | /* Tighten up footer */ 979 | .footer { 980 | padding-top: 20px; 981 | padding-bottom: 20px; 982 | } 983 | /* Unfloat the back to top in footer to prevent odd text wrapping */ 984 | .footer .pull-right { 985 | float: none; 986 | } 987 | } 988 | --------------------------------------------------------------------------------